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 */ 23package jdk.incubator.http.internal.hpack; 24 25import org.testng.annotations.Test; 26 27import java.io.UncheckedIOException; 28import java.net.ProtocolException; 29import java.nio.ByteBuffer; 30import java.util.Iterator; 31import java.util.LinkedList; 32import java.util.List; 33import java.util.function.Supplier; 34import java.util.stream.Collectors; 35 36import static org.testng.Assert.assertEquals; 37import static org.testng.Assert.assertNotNull; 38import 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// 44public final class DecoderTest { 45 46 // 47 // http://tools.ietf.org/html/rfc7541#appendix-C.2.1 48 // 49 @Test 50 public void example1() { 51 // @formatter:off 52 test("400a 6375 7374 6f6d 2d6b 6579 0d63 7573\n" + 53 "746f 6d2d 6865 6164 6572", 54 55 "[ 1] (s = 55) custom-key: custom-header\n" + 56 " Table size: 55", 57 58 "custom-key: custom-header"); 59 // @formatter:on 60 } 61 62 // 63 // http://tools.ietf.org/html/rfc7541#appendix-C.2.2 64 // 65 @Test 66 public void example2() { 67 // @formatter:off 68 test("040c 2f73 616d 706c 652f 7061 7468", 69 "empty.", 70 ":path: /sample/path"); 71 // @formatter:on 72 } 73 74 // 75 // http://tools.ietf.org/html/rfc7541#appendix-C.2.3 76 // 77 @Test 78 public void example3() { 79 // @formatter:off 80 test("1008 7061 7373 776f 7264 0673 6563 7265\n" + 81 "74", 82 "empty.", 83 "password: secret"); 84 // @formatter:on 85 } 86 87 // 88 // http://tools.ietf.org/html/rfc7541#appendix-C.2.4 89 // 90 @Test 91 public void example4() { 92 // @formatter:off 93 test("82", 94 "empty.", 95 ":method: GET"); 96 // @formatter:on 97 } 98 99 // 100 // http://tools.ietf.org/html/rfc7541#appendix-C.3 101 // 102 @Test 103 public void example5() { 104 // @formatter:off 105 Decoder d = new Decoder(256); 106 107 test(d, "8286 8441 0f77 7777 2e65 7861 6d70 6c65\n" + 108 "2e63 6f6d", 109 110 "[ 1] (s = 57) :authority: www.example.com\n" + 111 " Table size: 57", 112 113 ":method: GET\n" + 114 ":scheme: http\n" + 115 ":path: /\n" + 116 ":authority: www.example.com"); 117 118 test(d, "8286 84be 5808 6e6f 2d63 6163 6865", 119 120 "[ 1] (s = 53) cache-control: no-cache\n" + 121 "[ 2] (s = 57) :authority: www.example.com\n" + 122 " Table size: 110", 123 124 ":method: GET\n" + 125 ":scheme: http\n" + 126 ":path: /\n" + 127 ":authority: www.example.com\n" + 128 "cache-control: no-cache"); 129 130 test(d, "8287 85bf 400a 6375 7374 6f6d 2d6b 6579\n" + 131 "0c63 7573 746f 6d2d 7661 6c75 65", 132 133 "[ 1] (s = 54) custom-key: custom-value\n" + 134 "[ 2] (s = 53) cache-control: no-cache\n" + 135 "[ 3] (s = 57) :authority: www.example.com\n" + 136 " Table size: 164", 137 138 ":method: GET\n" + 139 ":scheme: https\n" + 140 ":path: /index.html\n" + 141 ":authority: www.example.com\n" + 142 "custom-key: custom-value"); 143 144 // @formatter:on 145 } 146 147 @Test 148 public void example5AllSplits() { 149 // @formatter:off 150 testAllSplits( 151 "8286 8441 0f77 7777 2e65 7861 6d70 6c65\n" + 152 "2e63 6f6d", 153 154 "[ 1] (s = 57) :authority: www.example.com\n" + 155 " Table size: 57", 156 157 ":method: GET\n" + 158 ":scheme: http\n" + 159 ":path: /\n" + 160 ":authority: www.example.com"); 161 // @formatter:on 162 } 163 164 // 165 // http://tools.ietf.org/html/rfc7541#appendix-C.4 166 // 167 @Test 168 public void example6() { 169 // @formatter:off 170 Decoder d = new Decoder(256); 171 172 test(d, "8286 8441 8cf1 e3c2 e5f2 3a6b a0ab 90f4\n" + 173 "ff", 174 175 "[ 1] (s = 57) :authority: www.example.com\n" + 176 " Table size: 57", 177 178 ":method: GET\n" + 179 ":scheme: http\n" + 180 ":path: /\n" + 181 ":authority: www.example.com"); 182 183 test(d, "8286 84be 5886 a8eb 1064 9cbf", 184 185 "[ 1] (s = 53) cache-control: no-cache\n" + 186 "[ 2] (s = 57) :authority: www.example.com\n" + 187 " Table size: 110", 188 189 ":method: GET\n" + 190 ":scheme: http\n" + 191 ":path: /\n" + 192 ":authority: www.example.com\n" + 193 "cache-control: no-cache"); 194 195 test(d, "8287 85bf 4088 25a8 49e9 5ba9 7d7f 8925\n" + 196 "a849 e95b b8e8 b4bf", 197 198 "[ 1] (s = 54) custom-key: custom-value\n" + 199 "[ 2] (s = 53) cache-control: no-cache\n" + 200 "[ 3] (s = 57) :authority: www.example.com\n" + 201 " Table size: 164", 202 203 ":method: GET\n" + 204 ":scheme: https\n" + 205 ":path: /index.html\n" + 206 ":authority: www.example.com\n" + 207 "custom-key: custom-value"); 208 // @formatter:on 209 } 210 211 // 212 // http://tools.ietf.org/html/rfc7541#appendix-C.5 213 // 214 @Test 215 public void example7() { 216 // @formatter:off 217 Decoder d = new Decoder(256); 218 219 test(d, "4803 3330 3258 0770 7269 7661 7465 611d\n" + 220 "4d6f 6e2c 2032 3120 4f63 7420 3230 3133\n" + 221 "2032 303a 3133 3a32 3120 474d 546e 1768\n" + 222 "7474 7073 3a2f 2f77 7777 2e65 7861 6d70\n" + 223 "6c65 2e63 6f6d", 224 225 "[ 1] (s = 63) location: https://www.example.com\n" + 226 "[ 2] (s = 65) date: Mon, 21 Oct 2013 20:13:21 GMT\n" + 227 "[ 3] (s = 52) cache-control: private\n" + 228 "[ 4] (s = 42) :status: 302\n" + 229 " Table size: 222", 230 231 ":status: 302\n" + 232 "cache-control: private\n" + 233 "date: Mon, 21 Oct 2013 20:13:21 GMT\n" + 234 "location: https://www.example.com"); 235 236 test(d, "4803 3330 37c1 c0bf", 237 238 "[ 1] (s = 42) :status: 307\n" + 239 "[ 2] (s = 63) location: https://www.example.com\n" + 240 "[ 3] (s = 65) date: Mon, 21 Oct 2013 20:13:21 GMT\n" + 241 "[ 4] (s = 52) cache-control: private\n" + 242 " Table size: 222", 243 244 ":status: 307\n" + 245 "cache-control: private\n" + 246 "date: Mon, 21 Oct 2013 20:13:21 GMT\n" + 247 "location: https://www.example.com"); 248 249 test(d, "88c1 611d 4d6f 6e2c 2032 3120 4f63 7420\n" + 250 "3230 3133 2032 303a 3133 3a32 3220 474d\n" + 251 "54c0 5a04 677a 6970 7738 666f 6f3d 4153\n" + 252 "444a 4b48 514b 425a 584f 5157 454f 5049\n" + 253 "5541 5851 5745 4f49 553b 206d 6178 2d61\n" + 254 "6765 3d33 3630 303b 2076 6572 7369 6f6e\n" + 255 "3d31", 256 257 "[ 1] (s = 98) set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1\n" + 258 "[ 2] (s = 52) content-encoding: gzip\n" + 259 "[ 3] (s = 65) date: Mon, 21 Oct 2013 20:13:22 GMT\n" + 260 " Table size: 215", 261 262 ":status: 200\n" + 263 "cache-control: private\n" + 264 "date: Mon, 21 Oct 2013 20:13:22 GMT\n" + 265 "location: https://www.example.com\n" + 266 "content-encoding: gzip\n" + 267 "set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"); 268 // @formatter:on 269 } 270 271 // 272 // http://tools.ietf.org/html/rfc7541#appendix-C.6 273 // 274 @Test 275 public void example8() { 276 // @formatter:off 277 Decoder d = new Decoder(256); 278 279 test(d, "4882 6402 5885 aec3 771a 4b61 96d0 7abe\n" + 280 "9410 54d4 44a8 2005 9504 0b81 66e0 82a6\n" + 281 "2d1b ff6e 919d 29ad 1718 63c7 8f0b 97c8\n" + 282 "e9ae 82ae 43d3", 283 284 "[ 1] (s = 63) location: https://www.example.com\n" + 285 "[ 2] (s = 65) date: Mon, 21 Oct 2013 20:13:21 GMT\n" + 286 "[ 3] (s = 52) cache-control: private\n" + 287 "[ 4] (s = 42) :status: 302\n" + 288 " Table size: 222", 289 290 ":status: 302\n" + 291 "cache-control: private\n" + 292 "date: Mon, 21 Oct 2013 20:13:21 GMT\n" + 293 "location: https://www.example.com"); 294 295 test(d, "4883 640e ffc1 c0bf", 296 297 "[ 1] (s = 42) :status: 307\n" + 298 "[ 2] (s = 63) location: https://www.example.com\n" + 299 "[ 3] (s = 65) date: Mon, 21 Oct 2013 20:13:21 GMT\n" + 300 "[ 4] (s = 52) cache-control: private\n" + 301 " Table size: 222", 302 303 ":status: 307\n" + 304 "cache-control: private\n" + 305 "date: Mon, 21 Oct 2013 20:13:21 GMT\n" + 306 "location: https://www.example.com"); 307 308 test(d, "88c1 6196 d07a be94 1054 d444 a820 0595\n" + 309 "040b 8166 e084 a62d 1bff c05a 839b d9ab\n" + 310 "77ad 94e7 821d d7f2 e6c7 b335 dfdf cd5b\n" + 311 "3960 d5af 2708 7f36 72c1 ab27 0fb5 291f\n" + 312 "9587 3160 65c0 03ed 4ee5 b106 3d50 07", 313 314 "[ 1] (s = 98) set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1\n" + 315 "[ 2] (s = 52) content-encoding: gzip\n" + 316 "[ 3] (s = 65) date: Mon, 21 Oct 2013 20:13:22 GMT\n" + 317 " Table size: 215", 318 319 ":status: 200\n" + 320 "cache-control: private\n" + 321 "date: Mon, 21 Oct 2013 20:13:22 GMT\n" + 322 "location: https://www.example.com\n" + 323 "content-encoding: gzip\n" + 324 "set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"); 325 // @formatter:on 326 } 327 328 @Test 329 // One of responses from Apache Server that helped to catch a bug 330 public void testX() { 331 Decoder d = new Decoder(4096); 332 // @formatter:off 333 test(d, "3fe1 1f88 6196 d07a be94 03ea 693f 7504\n" + 334 "00b6 a05c b827 2e32 fa98 b46f 769e 86b1\n" + 335 "9272 b025 da5c 2ea9 fd70 a8de 7fb5 3556\n" + 336 "5ab7 6ece c057 02e2 2ad2 17bf 6c96 d07a\n" + 337 "be94 0854 cb6d 4a08 0075 40bd 71b6 6e05\n" + 338 "a531 68df 0f13 8efe 4522 cd32 21b6 5686\n" + 339 "eb23 781f cf52 848f d24a 8f0f 0d02 3435\n" + 340 "5f87 497c a589 d34d 1f", 341 342 "[ 1] (s = 53) content-type: text/html\n" + 343 "[ 2] (s = 50) accept-ranges: bytes\n" + 344 "[ 3] (s = 74) last-modified: Mon, 11 Jun 2007 18:53:14 GMT\n" + 345 "[ 4] (s = 77) server: Apache/2.4.17 (Unix) OpenSSL/1.0.2e-dev\n" + 346 "[ 5] (s = 65) date: Mon, 09 Nov 2015 16:26:39 GMT\n" + 347 " Table size: 319", 348 349 ":status: 200\n" + 350 "date: Mon, 09 Nov 2015 16:26:39 GMT\n" + 351 "server: Apache/2.4.17 (Unix) OpenSSL/1.0.2e-dev\n" + 352 "last-modified: Mon, 11 Jun 2007 18:53:14 GMT\n" + 353 "etag: \"2d-432a5e4a73a80\"\n" + 354 "accept-ranges: bytes\n" + 355 "content-length: 45\n" + 356 "content-type: text/html"); 357 // @formatter:on 358 } 359 360 @Test 361 public void testX1() { 362 // Supplier of a decoder with a particular state 363 Supplier<Decoder> s = () -> { 364 Decoder d = new Decoder(4096); 365 // @formatter:off 366 test(d, "88 76 92 ca 54 a7 d7 f4 fa ec af ed 6d da 61 d7 bb 1e ad ff" + 367 "df 61 97 c3 61 be 94 13 4a 65 b6 a5 04 00 b8 a0 5a b8 db 77" + 368 "1b 71 4c 5a 37 ff 0f 0d 84 08 00 00 03", 369 370 "[ 1] (s = 65) date: Fri, 24 Jun 2016 14:55:56 GMT\n" + 371 "[ 2] (s = 59) server: Jetty(9.3.z-SNAPSHOT)\n" + 372 " Table size: 124", 373 374 ":status: 200\n" + 375 "server: Jetty(9.3.z-SNAPSHOT)\n" + 376 "date: Fri, 24 Jun 2016 14:55:56 GMT\n" + 377 "content-length: 100000" 378 ); 379 // @formatter:on 380 return d; 381 }; 382 // For all splits of the following data fed to the supplied decoder we 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 621 public void argsTestBothAreNull() { 622 Decoder decoder = new Decoder(4096); 623 assertVoidThrows(NullPointerException.class, 624 () -> decoder.decode(null, true, null)); 625 } 626 627 private static void test(String hexdump, 628 String headerTable, String headerList) { 629 test(new Decoder(4096), hexdump, headerTable, headerList); 630 } 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} 690