1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.apache.hc.core5.http.impl.nio;
29
30 import java.io.IOException;
31 import java.nio.ByteBuffer;
32 import java.nio.channels.ReadableByteChannel;
33 import java.nio.charset.StandardCharsets;
34 import java.util.List;
35
36 import org.apache.hc.core5.http.ConnectionClosedException;
37 import org.apache.hc.core5.http.Header;
38 import org.apache.hc.core5.http.MalformedChunkCodingException;
39 import org.apache.hc.core5.http.MessageConstraintException;
40 import org.apache.hc.core5.http.ReadableByteChannelMock;
41 import org.apache.hc.core5.http.TruncatedChunkException;
42 import org.apache.hc.core5.http.config.Http1Config;
43 import org.apache.hc.core5.http.impl.BasicHttpTransportMetrics;
44 import org.apache.hc.core5.http.nio.SessionInputBuffer;
45 import org.junit.jupiter.api.Assertions;
46 import org.junit.jupiter.api.Test;
47
48
49
50
51 public class TestChunkDecoder {
52
53 @Test
54 public void testBasicDecoding() throws Exception {
55 final String s = "5\r\n01234\r\n5\r\n56789\r\n6\r\nabcdef\r\n0\r\n\r\n";
56 final ReadableByteChannel channel = new ReadableByteChannelMock(
57 new String[] {s}, StandardCharsets.US_ASCII);
58 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
59 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
60 final ChunkDecoder decoder = new ChunkDecoder(channel, inbuf, metrics);
61
62 final ByteBuffer dst = ByteBuffer.allocate(1024);
63
64 int bytesRead = decoder.read(dst);
65 Assertions.assertEquals(16, bytesRead);
66 Assertions.assertEquals("0123456789abcdef", CodecTestUtils.convert(dst));
67 final List<? extends Header> trailers = decoder.getTrailers();
68 Assertions.assertNull(trailers);
69
70 dst.clear();
71 bytesRead = decoder.read(dst);
72 Assertions.assertEquals(-1, bytesRead);
73 Assertions.assertTrue(decoder.isCompleted());
74 Assertions.assertEquals("[chunk-coded; completed: true]", decoder.toString());
75 }
76
77 @Test
78 public void testComplexDecoding() throws Exception {
79 final String s = "10;key=\"value\"\r\n1234567890123456\r\n" +
80 "5\r\n12345\r\n5\r\n12345\r\n0\r\nFooter1: abcde\r\nFooter2: fghij\r\n\r\n";
81 final ReadableByteChannel channel = new ReadableByteChannelMock(
82 new String[] {s}, StandardCharsets.US_ASCII);
83
84 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
85 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
86 final ChunkDecoder decoder = new ChunkDecoder(channel, inbuf, metrics);
87
88 final ByteBuffer dst = ByteBuffer.allocate(1024);
89
90 int bytesRead = 0;
91 while (dst.hasRemaining() && !decoder.isCompleted()) {
92 final int i = decoder.read(dst);
93 if (i > 0) {
94 bytesRead += i;
95 }
96 }
97
98 Assertions.assertEquals(26, bytesRead);
99 Assertions.assertEquals("12345678901234561234512345", CodecTestUtils.convert(dst));
100
101 final List<? extends Header> trailers = decoder.getTrailers();
102 Assertions.assertEquals(2, trailers.size());
103 Assertions.assertEquals("Footer1", trailers.get(0).getName());
104 Assertions.assertEquals("abcde", trailers.get(0).getValue());
105 Assertions.assertEquals("Footer2", trailers.get(1).getName());
106 Assertions.assertEquals("fghij", trailers.get(1).getValue());
107
108 dst.clear();
109 bytesRead = decoder.read(dst);
110 Assertions.assertEquals(-1, bytesRead);
111 Assertions.assertTrue(decoder.isCompleted());
112 }
113
114 @Test
115 public void testDecodingWithSmallBuffer() throws Exception {
116 final String s1 = "5\r\n01234\r\n5\r\n5678";
117 final String s2 = "9\r\n6\r\nabcdef\r\n0\r\n\r\n";
118 final ReadableByteChannel channel = new ReadableByteChannelMock(
119 new String[] {s1, s2}, StandardCharsets.US_ASCII);
120
121 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
122 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
123 final ChunkDecoder decoder = new ChunkDecoder(channel, inbuf, metrics);
124
125 final ByteBuffer dst = ByteBuffer.allocate(1024);
126 final ByteBuffer tmp = ByteBuffer.allocate(4);
127
128 int bytesRead = 0;
129 while (dst.hasRemaining() && !decoder.isCompleted()) {
130 final int i = decoder.read(tmp);
131 if (i > 0) {
132 bytesRead += i;
133 }
134 tmp.flip();
135 dst.put(tmp);
136 tmp.compact();
137 }
138
139 Assertions.assertEquals(16, bytesRead);
140 Assertions.assertEquals("0123456789abcdef", CodecTestUtils.convert(dst));
141 Assertions.assertTrue(decoder.isCompleted());
142
143 dst.clear();
144 bytesRead = decoder.read(dst);
145 Assertions.assertEquals(-1, bytesRead);
146 Assertions.assertTrue(decoder.isCompleted());
147 }
148
149 @Test
150 public void testMalformedChunk() throws Exception {
151 final String s = "5\r\n01234----------------------------------------------------------" +
152 "-----------------------------------------------------------------------------" +
153 "-----------------------------------------------------------------------------";
154 final ReadableByteChannel channel = new ReadableByteChannelMock(
155 new String[] {s}, StandardCharsets.US_ASCII);
156
157 final SessionInputBuffer inbuf = new SessionInputBufferImpl(32, 32, 0, StandardCharsets.US_ASCII);
158 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
159 final ChunkDecoder decoder = new ChunkDecoder(channel, inbuf, metrics);
160
161 final ByteBuffer dst = ByteBuffer.allocate(1024);
162
163 Assertions.assertThrows(MalformedChunkCodingException.class, () -> decoder.read(dst));
164 }
165
166 @Test
167 public void testIncompleteChunkDecoding() throws Exception {
168 final String[] chunks = {
169 "10;",
170 "key=\"value\"\r",
171 "\n123456789012345",
172 "6\r\n5\r\n12",
173 "345\r\n6\r",
174 "\nabcdef\r",
175 "\n0\r\nFoot",
176 "er1: abcde\r\nFooter2: f",
177 "ghij\r\n\r\n"
178 };
179 final ReadableByteChannel channel = new ReadableByteChannelMock(
180 chunks, StandardCharsets.US_ASCII);
181
182 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
183 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
184 final ByteBuffer dst = ByteBuffer.allocate(1024);
185
186 final ChunkDecoder decoder = new ChunkDecoder(channel, inbuf, metrics);
187
188 int bytesRead = 0;
189 while (dst.hasRemaining() && !decoder.isCompleted()) {
190 final int i = decoder.read(dst);
191 if (i > 0) {
192 bytesRead += i;
193 }
194 }
195
196 Assertions.assertEquals(27, bytesRead);
197 Assertions.assertEquals("123456789012345612345abcdef", CodecTestUtils.convert(dst));
198 Assertions.assertTrue(decoder.isCompleted());
199
200 final List<? extends Header> trailers = decoder.getTrailers();
201 Assertions.assertEquals(2, trailers.size());
202 Assertions.assertEquals("Footer1", trailers.get(0).getName());
203 Assertions.assertEquals("abcde", trailers.get(0).getValue());
204 Assertions.assertEquals("Footer2", trailers.get(1).getName());
205 Assertions.assertEquals("fghij", trailers.get(1).getValue());
206
207 dst.clear();
208 bytesRead = decoder.read(dst);
209 Assertions.assertEquals(-1, bytesRead);
210 Assertions.assertTrue(decoder.isCompleted());
211 }
212
213 @Test
214 public void testMalformedChunkSizeDecoding() throws Exception {
215 final String s = "5\r\n01234\r\n5zz\r\n56789\r\n6\r\nabcdef\r\n0\r\n\r\n";
216 final ReadableByteChannel channel = new ReadableByteChannelMock(
217 new String[] {s}, StandardCharsets.US_ASCII);
218
219 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
220 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
221 final ChunkDecoder decoder = new ChunkDecoder(channel, inbuf, metrics);
222
223 final ByteBuffer dst = ByteBuffer.allocate(1024);
224 Assertions.assertThrows(MalformedChunkCodingException.class, () ->
225 decoder.read(dst));
226 }
227
228 @Test
229 public void testMalformedChunkEndingDecoding() throws Exception {
230 final String s = "5\r\n01234\r\n5\r\n56789\r\r6\r\nabcdef\r\n0\r\n\r\n";
231 final ReadableByteChannel channel = new ReadableByteChannelMock(
232 new String[] {s}, StandardCharsets.US_ASCII);
233
234 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
235 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
236 final ChunkDecoder decoder = new ChunkDecoder(channel, inbuf, metrics);
237
238 final ByteBuffer dst = ByteBuffer.allocate(1024);
239 Assertions.assertThrows(MalformedChunkCodingException.class, () ->
240 decoder.read(dst));
241 }
242
243 @Test
244 public void testMalformedChunkTruncatedChunk() throws Exception {
245 final String s = "3\r\n12";
246 final ReadableByteChannel channel = new ReadableByteChannelMock(
247 new String[] {s}, StandardCharsets.US_ASCII);
248
249 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
250 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
251 final ChunkDecoder decoder = new ChunkDecoder(channel, inbuf, metrics);
252
253 final ByteBuffer dst = ByteBuffer.allocate(1024);
254 Assertions.assertEquals(2, decoder.read(dst));
255 Assertions.assertThrows(TruncatedChunkException.class, () ->
256 decoder.read(dst));
257 }
258
259 @Test
260 public void testFoldedFooters() throws Exception {
261 final String s = "10;key=\"value\"\r\n1234567890123456\r\n" +
262 "5\r\n12345\r\n5\r\n12345\r\n0\r\nFooter1: abcde\r\n \r\n fghij\r\n\r\n";
263 final ReadableByteChannel channel = new ReadableByteChannelMock(
264 new String[] {s}, StandardCharsets.US_ASCII);
265
266 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
267 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
268 final ChunkDecoder decoder = new ChunkDecoder(channel, inbuf, metrics);
269
270 final ByteBuffer dst = ByteBuffer.allocate(1024);
271
272 final int bytesRead = decoder.read(dst);
273 Assertions.assertEquals(26, bytesRead);
274 Assertions.assertEquals("12345678901234561234512345", CodecTestUtils.convert(dst));
275
276 final List<? extends Header> trailers = decoder.getTrailers();
277 Assertions.assertEquals(1, trailers.size());
278 Assertions.assertEquals("Footer1", trailers.get(0).getName());
279 Assertions.assertEquals("abcde fghij", trailers.get(0).getValue());
280 }
281
282 @Test
283 public void testMalformedFooters() throws Exception {
284 final String s = "10;key=\"value\"\r\n1234567890123456\r\n" +
285 "5\r\n12345\r\n5\r\n12345\r\n0\r\nFooter1 abcde\r\n\r\n";
286 final ReadableByteChannel channel = new ReadableByteChannelMock(
287 new String[] {s}, StandardCharsets.US_ASCII);
288
289 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
290 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
291 final ChunkDecoder decoder = new ChunkDecoder(channel, inbuf, metrics);
292
293 final ByteBuffer dst = ByteBuffer.allocate(1024);
294 Assertions.assertThrows(IOException.class, () ->
295 decoder.read(dst));
296 }
297
298 @Test
299 public void testMissingLastCRLF() throws Exception {
300 final String s = "10\r\n1234567890123456\r\n" +
301 "5\r\n12345\r\n5\r\n12345";
302 final ReadableByteChannel channel = new ReadableByteChannelMock(
303 new String[] {s}, StandardCharsets.US_ASCII);
304
305 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
306 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
307 final ChunkDecoder decoder = new ChunkDecoder(channel, inbuf, metrics);
308
309 final ByteBuffer dst = ByteBuffer.allocate(1024);
310
311 Assertions.assertThrows(MalformedChunkCodingException.class, () -> {
312 while (dst.hasRemaining() && !decoder.isCompleted()) {
313 decoder.read(dst);
314 }
315 });
316 }
317
318 @Test
319 public void testMissingClosingChunk() throws Exception {
320 final String s = "10\r\n1234567890123456\r\n" +
321 "5\r\n12345\r\n5\r\n12345\r\n";
322 final ReadableByteChannel channel = new ReadableByteChannelMock(
323 new String[] {s}, StandardCharsets.US_ASCII);
324
325 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
326 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
327 final ChunkDecoder decoder = new ChunkDecoder(channel, inbuf, metrics);
328
329 final ByteBuffer dst = ByteBuffer.allocate(1024);
330
331 Assertions.assertThrows(ConnectionClosedException.class, () -> {
332 long bytesRead = 0;
333 try {
334 while (dst.hasRemaining() && !decoder.isCompleted()) {
335 final int i = decoder.read(dst);
336 if (i > 0) {
337 bytesRead += i;
338 }
339 }
340 } catch (final MalformedChunkCodingException ex) {
341 Assertions.assertEquals(26L, bytesRead);
342 Assertions.assertEquals("12345678901234561234512345", CodecTestUtils.convert(dst));
343 Assertions.assertTrue(decoder.isCompleted());
344 throw ex;
345 }
346 });
347 }
348
349 @Test
350 public void testReadingWitSmallBuffer() throws Exception {
351 final String s = "10\r\n1234567890123456\r\n" +
352 "40\r\n12345678901234561234567890123456" +
353 "12345678901234561234567890123456\r\n0\r\n";
354 final ReadableByteChannel channel = new ReadableByteChannelMock(
355 new String[] {s}, StandardCharsets.US_ASCII);
356
357 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
358 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
359 final ChunkDecoder decoder = new ChunkDecoder(channel, inbuf, metrics);
360
361 final ByteBuffer dst = ByteBuffer.allocate(1024);
362 final ByteBuffer tmp = ByteBuffer.allocate(10);
363
364 int bytesRead = 0;
365 while (dst.hasRemaining() && !decoder.isCompleted()) {
366 final int i = decoder.read(tmp);
367 if (i > 0) {
368 bytesRead += i;
369 tmp.flip();
370 dst.put(tmp);
371 tmp.compact();
372 }
373 }
374
375 Assertions.assertEquals(80, bytesRead);
376 Assertions.assertEquals("12345678901234561234567890123456" +
377 "12345678901234561234567890123456" +
378 "1234567890123456", CodecTestUtils.convert(dst));
379 Assertions.assertTrue(decoder.isCompleted());
380 }
381
382 @Test
383 public void testEndOfStreamConditionReadingFooters() throws Exception {
384 final String s = "10\r\n1234567890123456\r\n" +
385 "5\r\n12345\r\n5\r\n12345\r\n0\r\n";
386 final ReadableByteChannel channel = new ReadableByteChannelMock(
387 new String[] {s}, StandardCharsets.US_ASCII);
388
389 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
390 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
391 final ChunkDecoder decoder = new ChunkDecoder(channel, inbuf, metrics);
392
393 final ByteBuffer dst = ByteBuffer.allocate(1024);
394
395 int bytesRead = 0;
396 while (dst.hasRemaining() && !decoder.isCompleted()) {
397 final int i = decoder.read(dst);
398 if (i > 0) {
399 bytesRead += i;
400 }
401 }
402
403 Assertions.assertEquals(26, bytesRead);
404 Assertions.assertEquals("12345678901234561234512345", CodecTestUtils.convert(dst));
405 Assertions.assertTrue(decoder.isCompleted());
406 }
407
408 @Test
409 public void testTooLongChunkHeader() throws Exception {
410 final String s = "5; and some very looooong comment\r\n12345\r\n0\r\n";
411 final ReadableByteChannel channel1 = new ReadableByteChannelMock(
412 new String[] {s}, StandardCharsets.US_ASCII);
413
414 final BasicHttpTransportMetrics metrics1 = new BasicHttpTransportMetrics();
415 final SessionInputBuffer inbuf1 = new SessionInputBufferImpl(1024, 256);
416 final ChunkDecoder decoder1 = new ChunkDecoder(channel1, inbuf1, metrics1);
417
418 final ByteBuffer dst = ByteBuffer.allocate(1024);
419
420 while (dst.hasRemaining() && !decoder1.isCompleted()) {
421 decoder1.read(dst);
422 }
423 Assertions.assertEquals("12345", CodecTestUtils.convert(dst));
424 Assertions.assertTrue(decoder1.isCompleted());
425
426 final ReadableByteChannel channel2 = new ReadableByteChannelMock(
427 new String[] {s}, StandardCharsets.US_ASCII);
428
429 final SessionInputBuffer inbuf2 = new SessionInputBufferImpl(1024, 256, 10);
430 final BasicHttpTransportMetrics metrics2 = new BasicHttpTransportMetrics();
431 final ChunkDecoder decoder2 = new ChunkDecoder(channel2, inbuf2, metrics2);
432
433 dst.clear();
434 Assertions.assertThrows(MessageConstraintException.class, () -> decoder2.read(dst));
435 }
436
437 @Test
438 public void testTooLongFooter() throws Exception {
439 final String s = "10\r\n1234567890123456\r\n" +
440 "0\r\nFooter1: looooooooooooooooooooooooooooooooooooooooooooooooooooooog\r\n\r\n";
441 final ReadableByteChannel channel1 = new ReadableByteChannelMock(
442 new String[] {s}, StandardCharsets.US_ASCII);
443 final SessionInputBuffer inbuf1 = new SessionInputBufferImpl(1024, 256, 0);
444 final BasicHttpTransportMetrics metrics1 = new BasicHttpTransportMetrics();
445 final ChunkDecoder decoder1 = new ChunkDecoder(channel1, inbuf1, metrics1);
446
447 final ByteBuffer dst = ByteBuffer.allocate(1024);
448
449 final int bytesRead = decoder1.read(dst);
450 Assertions.assertEquals(16, bytesRead);
451 Assertions.assertEquals("1234567890123456", CodecTestUtils.convert(dst));
452 final List<? extends Header> trailers = decoder1.getTrailers();
453 Assertions.assertNotNull(trailers);
454 Assertions.assertEquals(1, trailers.size());
455
456 final ReadableByteChannel channel2 = new ReadableByteChannelMock(
457 new String[] {s}, StandardCharsets.US_ASCII);
458 final SessionInputBuffer inbuf2 = new SessionInputBufferImpl(1024, 256,
459 25, StandardCharsets.US_ASCII);
460 final BasicHttpTransportMetrics metrics2 = new BasicHttpTransportMetrics();
461 final ChunkDecoder decoder2 = new ChunkDecoder(channel2, inbuf2, metrics2);
462
463 dst.clear();
464 Assertions.assertThrows(MessageConstraintException.class, () -> decoder2.read(dst));
465 }
466
467 @Test
468 public void testTooLongFoldedFooter() throws Exception {
469 final String s = "10\r\n1234567890123456\r\n" +
470 "0\r\nFooter1: blah\r\n blah\r\n blah\r\n blah\r\n blah\r\n blah\r\n blah\r\n blah\r\n\r\n";
471 final ReadableByteChannel channel1 = new ReadableByteChannelMock(
472 new String[] {s}, StandardCharsets.US_ASCII);
473 final SessionInputBuffer inbuf1 = new SessionInputBufferImpl(1024, 256,
474 0, StandardCharsets.US_ASCII);
475 final BasicHttpTransportMetrics metrics1 = new BasicHttpTransportMetrics();
476 final ChunkDecoder decoder1 = new ChunkDecoder(channel1, inbuf1, metrics1);
477
478 final ByteBuffer dst = ByteBuffer.allocate(1024);
479
480 final int bytesRead = decoder1.read(dst);
481 Assertions.assertEquals(16, bytesRead);
482 Assertions.assertEquals("1234567890123456", CodecTestUtils.convert(dst));
483 final List<? extends Header> trailers = decoder1.getTrailers();
484 Assertions.assertNotNull(trailers);
485 Assertions.assertEquals(1, trailers.size());
486
487 final Http1Config http1Config = Http1Config.custom()
488 .setMaxLineLength(25)
489 .build();
490 final ReadableByteChannel channel2 = new ReadableByteChannelMock(
491 new String[] {s}, StandardCharsets.US_ASCII);
492 final SessionInputBuffer inbuf2 = new SessionInputBufferImpl(1024, 256,0, StandardCharsets.US_ASCII);
493 final BasicHttpTransportMetrics metrics2 = new BasicHttpTransportMetrics();
494 final ChunkDecoder decoder2 = new ChunkDecoder(channel2, inbuf2, http1Config, metrics2);
495
496 dst.clear();
497 Assertions.assertThrows(MessageConstraintException.class, () -> decoder2.read(dst));
498 }
499
500 @Test
501 public void testTooManyFooters() throws Exception {
502 final String s = "10\r\n1234567890123456\r\n" +
503 "0\r\nFooter1: blah\r\nFooter2: blah\r\nFooter3: blah\r\nFooter4: blah\r\n\r\n";
504 final ReadableByteChannel channel1 = new ReadableByteChannelMock(
505 new String[] {s}, StandardCharsets.US_ASCII);
506 final SessionInputBuffer inbuf1 = new SessionInputBufferImpl(1024, 256,0, StandardCharsets.US_ASCII);
507 final BasicHttpTransportMetrics metrics1 = new BasicHttpTransportMetrics();
508 final ChunkDecoder decoder1 = new ChunkDecoder(channel1, inbuf1, metrics1);
509
510 final ByteBuffer dst = ByteBuffer.allocate(1024);
511
512 final int bytesRead = decoder1.read(dst);
513 Assertions.assertEquals(16, bytesRead);
514 Assertions.assertEquals("1234567890123456", CodecTestUtils.convert(dst));
515 final List<? extends Header> trailers = decoder1.getTrailers();
516 Assertions.assertNotNull(trailers);
517 Assertions.assertEquals(4, trailers.size());
518
519 final Http1Config http1Config = Http1Config.custom()
520 .setMaxHeaderCount(3).build();
521 final ReadableByteChannel channel2 = new ReadableByteChannelMock(
522 new String[] {s}, StandardCharsets.US_ASCII);
523 final SessionInputBuffer inbuf2 = new SessionInputBufferImpl(1024, 256,
524 0, StandardCharsets.US_ASCII);
525 final BasicHttpTransportMetrics metrics2 = new BasicHttpTransportMetrics();
526 final ChunkDecoder decoder2 = new ChunkDecoder(channel2, inbuf2, http1Config, metrics2);
527
528 dst.clear();
529 Assertions.assertThrows(MessageConstraintException.class, () -> decoder2.read(dst));
530 }
531
532 @Test
533 public void testInvalidConstructor() {
534 final ReadableByteChannel channel = new ReadableByteChannelMock(
535 new String[] {"stuff;", "more stuff"}, StandardCharsets.US_ASCII);
536
537 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
538 Assertions.assertThrows(NullPointerException.class, () -> new ChunkDecoder(null, null, null));
539 Assertions.assertThrows(NullPointerException.class, () -> new ChunkDecoder(channel, inbuf, null));
540 }
541
542 @Test
543 public void testInvalidInput() throws Exception {
544 final String s = "10;key=\"value\"\r\n1234567890123456\r\n" +
545 "5\r\n12345\r\n5\r\n12345\r\n0\r\nFooter1 abcde\r\n\r\n";
546 final ReadableByteChannel channel = new ReadableByteChannelMock(
547 new String[] {s}, StandardCharsets.US_ASCII);
548
549 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
550 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
551 final ChunkDecoder decoder = new ChunkDecoder(channel, inbuf, metrics);
552 Assertions.assertThrows(NullPointerException.class, () ->
553 decoder.read(null));
554 }
555
556 @Test
557 public void testHugeChunk() throws Exception {
558 final String s = "1234567890abcdef\r\n0123456789abcdef";
559 final ReadableByteChannel channel = new ReadableByteChannelMock(new String[] {s}, StandardCharsets.US_ASCII);
560 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
561 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
562 final ChunkDecoder decoder = new ChunkDecoder(channel, inbuf, metrics);
563
564 final ByteBuffer dst = ByteBuffer.allocate(4);
565
566 int bytesRead = decoder.read(dst);
567 Assertions.assertEquals(4, bytesRead);
568 Assertions.assertEquals("0123", CodecTestUtils.convert(dst));
569 dst.clear();
570 bytesRead = decoder.read(dst);
571 Assertions.assertEquals(4, bytesRead);
572 Assertions.assertEquals("4567", CodecTestUtils.convert(dst));
573 }
574
575 }