< prev index next >

test/jdk/java/net/httpclient/http2/jdk.incubator.httpclient/jdk/incubator/http/internal/hpack/DecoderTest.java

Print this page


   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 }
< prev index next >