1 /* 2 * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package jdk.incubator.http.internal.hpack; 24 25 import org.testng.annotations.Test; 26 27 import java.io.UncheckedIOException; 28 import java.net.ProtocolException; 29 import java.nio.ByteBuffer; 30 import java.util.Iterator; 31 import java.util.LinkedList; 32 import java.util.List; 33 import java.util.function.Supplier; 34 import java.util.stream.Collectors; 35 36 import static org.testng.Assert.assertEquals; 37 import static org.testng.Assert.assertNotNull; 38 import static jdk.incubator.http.internal.hpack.TestHelper.*; 39 40 // 41 // Tests whose names start with "testX" are the ones captured from real HPACK 42 // use cases 43 // 44 public final class DecoderTest { 45 46 // 47 // http://tools.ietf.org/html/rfc7541#appendix-C.2.1 48 // 383 // must get what's expected 384 // @formatter:off 385 testAllSplits(s, 386 "88 bf be 0f 0d 84 08 00 00 03", 387 388 "[ 1] (s = 65) date: Fri, 24 Jun 2016 14:55:56 GMT\n" + 389 "[ 2] (s = 59) server: Jetty(9.3.z-SNAPSHOT)\n" + 390 " Table size: 124", 391 392 ":status: 200\n" + 393 "server: Jetty(9.3.z-SNAPSHOT)\n" + 394 "date: Fri, 24 Jun 2016 14:55:56 GMT\n" + 395 "content-length: 100000"); 396 // @formatter:on 397 } 398 399 // 400 // This test is missing in the spec 401 // 402 @Test 403 public void sizeUpdate() { 404 Decoder d = new Decoder(4096); 405 assertEquals(d.getTable().maxSize(), 4096); 406 d.decode(ByteBuffer.wrap(new byte[]{0b00111110}), true, nopCallback()); // newSize = 30 407 assertEquals(d.getTable().maxSize(), 30); 408 } 409 410 @Test 411 public void incorrectSizeUpdate() { 412 ByteBuffer b = ByteBuffer.allocate(8); 413 Encoder e = new Encoder(8192) { 414 @Override 415 protected int calculateCapacity(int maxCapacity) { 416 return maxCapacity; 417 } 418 }; 419 e.header("a", "b"); 420 e.encode(b); 421 b.flip(); 422 { 423 Decoder d = new Decoder(4096); 424 UncheckedIOException ex = assertVoidThrows(UncheckedIOException.class, 425 () -> d.decode(b, true, (name, value) -> { })); 426 427 assertNotNull(ex.getCause()); 428 assertEquals(ex.getCause().getClass(), ProtocolException.class); 429 } 430 b.flip(); 431 { 432 Decoder d = new Decoder(4096); 433 UncheckedIOException ex = assertVoidThrows(UncheckedIOException.class, 434 () -> d.decode(b, false, (name, value) -> { })); 435 436 assertNotNull(ex.getCause()); 437 assertEquals(ex.getCause().getClass(), ProtocolException.class); 438 } 439 } 440 441 @Test 442 public void corruptedHeaderBlockInteger() { 443 Decoder d = new Decoder(4096); 444 ByteBuffer data = ByteBuffer.wrap(new byte[]{ 445 (byte) 0b11111111, // indexed 446 (byte) 0b10011010 // 25 + ... 447 }); 448 UncheckedIOException e = assertVoidThrows(UncheckedIOException.class, 449 () -> d.decode(data, true, nopCallback())); 450 assertNotNull(e.getCause()); 451 assertEquals(e.getCause().getClass(), ProtocolException.class); 452 assertExceptionMessageContains(e, "Unexpected end of header block"); 453 } 454 455 // 5.1. Integer Representation 456 // ... 457 // Integer encodings that exceed implementation limits -- in value or octet 458 // length -- MUST be treated as decoding errors. Different limits can 459 // be set for each of the different uses of integers, based on 460 // implementation constraints. 461 @Test 462 public void headerBlockIntegerNoOverflow() { 463 Decoder d = new Decoder(4096); 464 ByteBuffer data = ByteBuffer.wrap(new byte[]{ 465 (byte) 0b11111111, // indexed + 127 466 // Integer.MAX_VALUE - 127 (base 128, little-endian): 467 (byte) 0b10000000, 468 (byte) 0b11111111, 469 (byte) 0b11111111, 470 (byte) 0b11111111, 471 (byte) 0b00000111 472 }); 473 474 IllegalArgumentException e = assertVoidThrows(IllegalArgumentException.class, 475 () -> d.decode(data, true, nopCallback())); 476 477 assertExceptionMessageContains(e, "index=2147483647"); 478 } 479 480 @Test 481 public void headerBlockIntegerOverflow() { 482 Decoder d = new Decoder(4096); 483 ByteBuffer data = ByteBuffer.wrap(new byte[]{ 484 (byte) 0b11111111, // indexed + 127 485 // Integer.MAX_VALUE - 127 + 1 (base 128, little endian): 486 (byte) 0b10000001, 487 (byte) 0b11111111, 488 (byte) 0b11111111, 489 (byte) 0b11111111, 490 (byte) 0b00000111 491 }); 492 493 IllegalArgumentException e = assertVoidThrows(IllegalArgumentException.class, 494 () -> d.decode(data, true, nopCallback())); 495 496 assertExceptionMessageContains(e, "Integer overflow"); 497 } 498 499 @Test 500 public void corruptedHeaderBlockString1() { 501 Decoder d = new Decoder(4096); 502 ByteBuffer data = ByteBuffer.wrap(new byte[]{ 503 0b00001111, // literal, index=15 504 0b00000000, 505 0b00001000, // huffman=false, length=8 506 0b00000000, // \ 507 0b00000000, // but only 3 octets available... 508 0b00000000 // / 509 }); 510 UncheckedIOException e = assertVoidThrows(UncheckedIOException.class, 511 () -> d.decode(data, true, nopCallback())); 512 assertNotNull(e.getCause()); 513 assertEquals(e.getCause().getClass(), ProtocolException.class); 514 assertExceptionMessageContains(e, "Unexpected end of header block"); 515 } 516 517 @Test 518 public void corruptedHeaderBlockString2() { 519 Decoder d = new Decoder(4096); 520 ByteBuffer data = ByteBuffer.wrap(new byte[]{ 521 0b00001111, // literal, index=15 522 0b00000000, 523 (byte) 0b10001000, // huffman=true, length=8 524 0b00000000, // \ 525 0b00000000, // \ 526 0b00000000, // but only 5 octets available... 527 0b00000000, // / 528 0b00000000 // / 529 }); 530 UncheckedIOException e = assertVoidThrows(UncheckedIOException.class, 531 () -> d.decode(data, true, nopCallback())); 532 assertNotNull(e.getCause()); 533 assertEquals(e.getCause().getClass(), ProtocolException.class); 534 assertExceptionMessageContains(e, "Unexpected end of header block"); 535 } 536 537 // 5.2. String Literal Representation 538 // ...A Huffman-encoded string literal containing the EOS symbol MUST be 539 // treated as a decoding error... 540 @Test 541 public void corruptedHeaderBlockHuffmanStringEOS() { 542 Decoder d = new Decoder(4096); 543 ByteBuffer data = ByteBuffer.wrap(new byte[]{ 544 0b00001111, // literal, index=15 545 0b00000000, 546 (byte) 0b10000110, // huffman=true, length=6 547 0b00011001, 0b01001101, (byte) 0b11111111, 548 (byte) 0b11111111, (byte) 0b11111111, (byte) 0b11111100 549 }); 550 IllegalArgumentException e = assertVoidThrows(IllegalArgumentException.class, 551 () -> d.decode(data, true, nopCallback())); 552 553 assertExceptionMessageContains(e, "Encountered EOS"); 554 } 555 556 // 5.2. String Literal Representation 557 // ...A padding strictly longer than 7 bits MUST be treated as a decoding 558 // error... 559 @Test 560 public void corruptedHeaderBlockHuffmanStringLongPadding1() { 561 Decoder d = new Decoder(4096); 562 ByteBuffer data = ByteBuffer.wrap(new byte[]{ 563 0b00001111, // literal, index=15 564 0b00000000, 565 (byte) 0b10000011, // huffman=true, length=3 566 0b00011001, 0b01001101, (byte) 0b11111111 567 // len("aei") + len(padding) = (5 + 5 + 5) + (9) 568 }); 569 IllegalArgumentException e = assertVoidThrows(IllegalArgumentException.class, 570 () -> d.decode(data, true, nopCallback())); 571 572 assertExceptionMessageContains(e, "Padding is too long", "len=9"); 573 } 574 575 @Test 576 public void corruptedHeaderBlockHuffmanStringLongPadding2() { 577 Decoder d = new Decoder(4096); 578 ByteBuffer data = ByteBuffer.wrap(new byte[]{ 579 0b00001111, // literal, index=15 580 0b00000000, 581 (byte) 0b10000011, // huffman=true, length=3 582 0b00011001, 0b01111010, (byte) 0b11111111 583 // len("aek") + len(padding) = (5 + 5 + 7) + (7) 584 }); 585 assertVoidDoesNotThrow(() -> d.decode(data, true, nopCallback())); 586 } 587 588 // 5.2. String Literal Representation 589 // ...A padding not corresponding to the most significant bits of the code 590 // for the EOS symbol MUST be treated as a decoding error... 591 @Test 592 public void corruptedHeaderBlockHuffmanStringNotEOSPadding() { 593 Decoder d = new Decoder(4096); 594 ByteBuffer data = ByteBuffer.wrap(new byte[]{ 595 0b00001111, // literal, index=15 596 0b00000000, 597 (byte) 0b10000011, // huffman=true, length=3 598 0b00011001, 0b01111010, (byte) 0b11111110 599 }); 600 IllegalArgumentException e = assertVoidThrows(IllegalArgumentException.class, 601 () -> d.decode(data, true, nopCallback())); 602 603 assertExceptionMessageContains(e, "Not a EOS prefix"); 604 } 605 606 @Test 607 public void argsTestBiConsumerIsNull() { 608 Decoder decoder = new Decoder(4096); 609 assertVoidThrows(NullPointerException.class, 610 () -> decoder.decode(ByteBuffer.allocate(16), true, null)); 611 } 612 613 @Test 614 public void argsTestByteBufferIsNull() { 615 Decoder decoder = new Decoder(4096); 616 assertVoidThrows(NullPointerException.class, 617 () -> decoder.decode(null, true, nopCallback())); 618 } 619 620 @Test 631 632 private static void testAllSplits(String hexdump, 633 String expectedHeaderTable, 634 String expectedHeaderList) { 635 testAllSplits(() -> new Decoder(256), hexdump, expectedHeaderTable, expectedHeaderList); 636 } 637 638 private static void testAllSplits(Supplier<Decoder> supplier, String hexdump, 639 String expectedHeaderTable, String expectedHeaderList) { 640 ByteBuffer source = SpecHelper.toBytes(hexdump); 641 642 BuffersTestingKit.forEachSplit(source, iterable -> { 643 List<String> actual = new LinkedList<>(); 644 Iterator<? extends ByteBuffer> i = iterable.iterator(); 645 if (!i.hasNext()) { 646 return; 647 } 648 Decoder d = supplier.get(); 649 do { 650 ByteBuffer n = i.next(); 651 d.decode(n, !i.hasNext(), (name, value) -> { 652 if (value == null) { 653 actual.add(name.toString()); 654 } else { 655 actual.add(name + ": " + value); 656 } 657 }); 658 } while (i.hasNext()); 659 assertEquals(d.getTable().getStateString(), expectedHeaderTable); 660 assertEquals(actual.stream().collect(Collectors.joining("\n")), expectedHeaderList); 661 }); 662 } 663 664 // 665 // Sometimes we need to keep the same decoder along several runs, 666 // as it models the same connection 667 // 668 private static void test(Decoder d, String hexdump, 669 String expectedHeaderTable, String expectedHeaderList) { 670 671 ByteBuffer source = SpecHelper.toBytes(hexdump); 672 673 List<String> actual = new LinkedList<>(); 674 d.decode(source, true, (name, value) -> { 675 if (value == null) { 676 actual.add(name.toString()); 677 } else { 678 actual.add(name + ": " + value); 679 } 680 }); 681 682 assertEquals(d.getTable().getStateString(), expectedHeaderTable); 683 assertEquals(actual.stream().collect(Collectors.joining("\n")), expectedHeaderList); 684 } 685 686 private static DecodingCallback nopCallback() { 687 return (t, u) -> { }; 688 } 689 } | 1 /* 2 * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package jdk.incubator.http.internal.hpack; 24 25 import org.testng.annotations.Test; 26 27 import java.io.IOException; 28 import java.io.UncheckedIOException; 29 import java.nio.ByteBuffer; 30 import java.util.Iterator; 31 import java.util.LinkedList; 32 import java.util.List; 33 import java.util.function.Supplier; 34 import java.util.stream.Collectors; 35 36 import static org.testng.Assert.assertEquals; 37 import static org.testng.Assert.assertNotNull; 38 import static jdk.incubator.http.internal.hpack.TestHelper.*; 39 40 // 41 // Tests whose names start with "testX" are the ones captured from real HPACK 42 // use cases 43 // 44 public final class DecoderTest { 45 46 // 47 // http://tools.ietf.org/html/rfc7541#appendix-C.2.1 48 // 383 // must get what's expected 384 // @formatter:off 385 testAllSplits(s, 386 "88 bf be 0f 0d 84 08 00 00 03", 387 388 "[ 1] (s = 65) date: Fri, 24 Jun 2016 14:55:56 GMT\n" + 389 "[ 2] (s = 59) server: Jetty(9.3.z-SNAPSHOT)\n" + 390 " Table size: 124", 391 392 ":status: 200\n" + 393 "server: Jetty(9.3.z-SNAPSHOT)\n" + 394 "date: Fri, 24 Jun 2016 14:55:56 GMT\n" + 395 "content-length: 100000"); 396 // @formatter:on 397 } 398 399 // 400 // This test is missing in the spec 401 // 402 @Test 403 public void sizeUpdate() throws IOException { 404 Decoder d = new Decoder(4096); 405 assertEquals(d.getTable().maxSize(), 4096); 406 d.decode(ByteBuffer.wrap(new byte[]{0b00111110}), true, nopCallback()); // newSize = 30 407 assertEquals(d.getTable().maxSize(), 30); 408 } 409 410 @Test 411 public void incorrectSizeUpdate() { 412 ByteBuffer b = ByteBuffer.allocate(8); 413 Encoder e = new Encoder(8192) { 414 @Override 415 protected int calculateCapacity(int maxCapacity) { 416 return maxCapacity; 417 } 418 }; 419 e.header("a", "b"); 420 e.encode(b); 421 b.flip(); 422 { 423 Decoder d = new Decoder(4096); 424 assertVoidThrows(IOException.class, 425 () -> d.decode(b, true, (name, value) -> { })); 426 } 427 b.flip(); 428 { 429 Decoder d = new Decoder(4096); 430 assertVoidThrows(IOException.class, 431 () -> d.decode(b, false, (name, value) -> { })); 432 } 433 } 434 435 @Test 436 public void corruptedHeaderBlockInteger() { 437 Decoder d = new Decoder(4096); 438 ByteBuffer data = ByteBuffer.wrap(new byte[]{ 439 (byte) 0b11111111, // indexed 440 (byte) 0b10011010 // 25 + ... 441 }); 442 IOException e = assertVoidThrows(IOException.class, 443 () -> d.decode(data, true, nopCallback())); 444 assertExceptionMessageContains(e, "Unexpected end of header block"); 445 } 446 447 // 5.1. Integer Representation 448 // ... 449 // Integer encodings that exceed implementation limits -- in value or octet 450 // length -- MUST be treated as decoding errors. Different limits can 451 // be set for each of the different uses of integers, based on 452 // implementation constraints. 453 @Test 454 public void headerBlockIntegerNoOverflow() { 455 Decoder d = new Decoder(4096); 456 ByteBuffer data = ByteBuffer.wrap(new byte[]{ 457 (byte) 0b11111111, // indexed + 127 458 // Integer.MAX_VALUE - 127 (base 128, little-endian): 459 (byte) 0b10000000, 460 (byte) 0b11111111, 461 (byte) 0b11111111, 462 (byte) 0b11111111, 463 (byte) 0b00000111 464 }); 465 466 IOException e = assertVoidThrows(IOException.class, 467 () -> d.decode(data, true, nopCallback())); 468 469 assertExceptionMessageContains(e.getCause(), "index=2147483647"); 470 } 471 472 @Test 473 public void headerBlockIntegerOverflow() { 474 Decoder d = new Decoder(4096); 475 ByteBuffer data = ByteBuffer.wrap(new byte[]{ 476 (byte) 0b11111111, // indexed + 127 477 // Integer.MAX_VALUE - 127 + 1 (base 128, little endian): 478 (byte) 0b10000001, 479 (byte) 0b11111111, 480 (byte) 0b11111111, 481 (byte) 0b11111111, 482 (byte) 0b00000111 483 }); 484 485 IOException e = assertVoidThrows(IOException.class, 486 () -> d.decode(data, true, nopCallback())); 487 488 assertExceptionMessageContains(e, "Integer overflow"); 489 } 490 491 @Test 492 public void corruptedHeaderBlockString1() { 493 Decoder d = new Decoder(4096); 494 ByteBuffer data = ByteBuffer.wrap(new byte[]{ 495 0b00001111, // literal, index=15 496 0b00000000, 497 0b00001000, // huffman=false, length=8 498 0b00000000, // \ 499 0b00000000, // but only 3 octets available... 500 0b00000000 // / 501 }); 502 IOException e = assertVoidThrows(IOException.class, 503 () -> d.decode(data, true, nopCallback())); 504 assertExceptionMessageContains(e, "Unexpected end of header block"); 505 } 506 507 @Test 508 public void corruptedHeaderBlockString2() { 509 Decoder d = new Decoder(4096); 510 ByteBuffer data = ByteBuffer.wrap(new byte[]{ 511 0b00001111, // literal, index=15 512 0b00000000, 513 (byte) 0b10001000, // huffman=true, length=8 514 0b00000000, // \ 515 0b00000000, // \ 516 0b00000000, // but only 5 octets available... 517 0b00000000, // / 518 0b00000000 // / 519 }); 520 IOException e = assertVoidThrows(IOException.class, 521 () -> d.decode(data, true, nopCallback())); 522 assertExceptionMessageContains(e, "Unexpected end of header block"); 523 } 524 525 // 5.2. String Literal Representation 526 // ...A Huffman-encoded string literal containing the EOS symbol MUST be 527 // treated as a decoding error... 528 @Test 529 public void corruptedHeaderBlockHuffmanStringEOS() { 530 Decoder d = new Decoder(4096); 531 ByteBuffer data = ByteBuffer.wrap(new byte[]{ 532 0b00001111, // literal, index=15 533 0b00000000, 534 (byte) 0b10000110, // huffman=true, length=6 535 0b00011001, 0b01001101, (byte) 0b11111111, 536 (byte) 0b11111111, (byte) 0b11111111, (byte) 0b11111100 537 }); 538 IOException e = assertVoidThrows(IOException.class, 539 () -> d.decode(data, true, nopCallback())); 540 541 assertExceptionMessageContains(e, "Encountered EOS"); 542 } 543 544 // 5.2. String Literal Representation 545 // ...A padding strictly longer than 7 bits MUST be treated as a decoding 546 // error... 547 @Test 548 public void corruptedHeaderBlockHuffmanStringLongPadding1() { 549 Decoder d = new Decoder(4096); 550 ByteBuffer data = ByteBuffer.wrap(new byte[]{ 551 0b00001111, // literal, index=15 552 0b00000000, 553 (byte) 0b10000011, // huffman=true, length=3 554 0b00011001, 0b01001101, (byte) 0b11111111 555 // len("aei") + len(padding) = (5 + 5 + 5) + (9) 556 }); 557 IOException e = assertVoidThrows(IOException.class, 558 () -> d.decode(data, true, nopCallback())); 559 560 assertExceptionMessageContains(e, "Padding is too long", "len=9"); 561 } 562 563 @Test 564 public void corruptedHeaderBlockHuffmanStringLongPadding2() { 565 Decoder d = new Decoder(4096); 566 ByteBuffer data = ByteBuffer.wrap(new byte[]{ 567 0b00001111, // literal, index=15 568 0b00000000, 569 (byte) 0b10000011, // huffman=true, length=3 570 0b00011001, 0b01111010, (byte) 0b11111111 571 // len("aek") + len(padding) = (5 + 5 + 7) + (7) 572 }); 573 assertVoidDoesNotThrow(() -> d.decode(data, true, nopCallback())); 574 } 575 576 // 5.2. String Literal Representation 577 // ...A padding not corresponding to the most significant bits of the code 578 // for the EOS symbol MUST be treated as a decoding error... 579 @Test 580 public void corruptedHeaderBlockHuffmanStringNotEOSPadding() { 581 Decoder d = new Decoder(4096); 582 ByteBuffer data = ByteBuffer.wrap(new byte[]{ 583 0b00001111, // literal, index=15 584 0b00000000, 585 (byte) 0b10000011, // huffman=true, length=3 586 0b00011001, 0b01111010, (byte) 0b11111110 587 }); 588 IOException e = assertVoidThrows(IOException.class, 589 () -> d.decode(data, true, nopCallback())); 590 591 assertExceptionMessageContains(e, "Not a EOS prefix"); 592 } 593 594 @Test 595 public void argsTestBiConsumerIsNull() { 596 Decoder decoder = new Decoder(4096); 597 assertVoidThrows(NullPointerException.class, 598 () -> decoder.decode(ByteBuffer.allocate(16), true, null)); 599 } 600 601 @Test 602 public void argsTestByteBufferIsNull() { 603 Decoder decoder = new Decoder(4096); 604 assertVoidThrows(NullPointerException.class, 605 () -> decoder.decode(null, true, nopCallback())); 606 } 607 608 @Test 619 620 private static void testAllSplits(String hexdump, 621 String expectedHeaderTable, 622 String expectedHeaderList) { 623 testAllSplits(() -> new Decoder(256), hexdump, expectedHeaderTable, expectedHeaderList); 624 } 625 626 private static void testAllSplits(Supplier<Decoder> supplier, String hexdump, 627 String expectedHeaderTable, String expectedHeaderList) { 628 ByteBuffer source = SpecHelper.toBytes(hexdump); 629 630 BuffersTestingKit.forEachSplit(source, iterable -> { 631 List<String> actual = new LinkedList<>(); 632 Iterator<? extends ByteBuffer> i = iterable.iterator(); 633 if (!i.hasNext()) { 634 return; 635 } 636 Decoder d = supplier.get(); 637 do { 638 ByteBuffer n = i.next(); 639 try { 640 d.decode(n, !i.hasNext(), (name, value) -> { 641 if (value == null) { 642 actual.add(name.toString()); 643 } else { 644 actual.add(name + ": " + value); 645 } 646 }); 647 } catch (IOException e) { 648 throw new UncheckedIOException(e); 649 } 650 } while (i.hasNext()); 651 assertEquals(d.getTable().getStateString(), expectedHeaderTable); 652 assertEquals(actual.stream().collect(Collectors.joining("\n")), expectedHeaderList); 653 }); 654 } 655 656 // 657 // Sometimes we need to keep the same decoder along several runs, 658 // as it models the same connection 659 // 660 private static void test(Decoder d, String hexdump, 661 String expectedHeaderTable, String expectedHeaderList) { 662 663 ByteBuffer source = SpecHelper.toBytes(hexdump); 664 665 List<String> actual = new LinkedList<>(); 666 try { 667 d.decode(source, true, (name, value) -> { 668 if (value == null) { 669 actual.add(name.toString()); 670 } else { 671 actual.add(name + ": " + value); 672 } 673 }); 674 } catch (IOException e) { 675 throw new UncheckedIOException(e); 676 } 677 678 assertEquals(d.getTable().getStateString(), expectedHeaderTable); 679 assertEquals(actual.stream().collect(Collectors.joining("\n")), expectedHeaderList); 680 } 681 682 private static DecodingCallback nopCallback() { 683 return (t, u) -> { }; 684 } 685 } |