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.Assert;
46 import org.junit.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 Assert.assertEquals(16, bytesRead);
66 Assert.assertEquals("0123456789abcdef", CodecTestUtils.convert(dst));
67 final List<? extends Header> trailers = decoder.getTrailers();
68 Assert.assertEquals(null, trailers);
69
70 dst.clear();
71 bytesRead = decoder.read(dst);
72 Assert.assertEquals(-1, bytesRead);
73 Assert.assertTrue(decoder.isCompleted());
74 Assert.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 Assert.assertEquals(26, bytesRead);
99 Assert.assertEquals("12345678901234561234512345", CodecTestUtils.convert(dst));
100
101 final List<? extends Header> trailers = decoder.getTrailers();
102 Assert.assertEquals(2, trailers.size());
103 Assert.assertEquals("Footer1", trailers.get(0).getName());
104 Assert.assertEquals("abcde", trailers.get(0).getValue());
105 Assert.assertEquals("Footer2", trailers.get(1).getName());
106 Assert.assertEquals("fghij", trailers.get(1).getValue());
107
108 dst.clear();
109 bytesRead = decoder.read(dst);
110 Assert.assertEquals(-1, bytesRead);
111 Assert.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 Assert.assertEquals(16, bytesRead);
140 Assert.assertEquals("0123456789abcdef", CodecTestUtils.convert(dst));
141 Assert.assertTrue(decoder.isCompleted());
142
143 dst.clear();
144 bytesRead = decoder.read(dst);
145 Assert.assertEquals(-1, bytesRead);
146 Assert.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 try {
164 decoder.read(dst);
165 Assert.fail("MalformedChunkCodingException should have been thrown");
166 } catch (final MalformedChunkCodingException ex) {
167
168 }
169 }
170
171 @Test
172 public void testIncompleteChunkDecoding() throws Exception {
173 final String[] chunks = {
174 "10;",
175 "key=\"value\"\r",
176 "\n123456789012345",
177 "6\r\n5\r\n12",
178 "345\r\n6\r",
179 "\nabcdef\r",
180 "\n0\r\nFoot",
181 "er1: abcde\r\nFooter2: f",
182 "ghij\r\n\r\n"
183 };
184 final ReadableByteChannel channel = new ReadableByteChannelMock(
185 chunks, StandardCharsets.US_ASCII);
186
187 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
188 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
189 final ByteBuffer dst = ByteBuffer.allocate(1024);
190
191 final ChunkDecoder decoder = new ChunkDecoder(channel, inbuf, metrics);
192
193 int bytesRead = 0;
194 while (dst.hasRemaining() && !decoder.isCompleted()) {
195 final int i = decoder.read(dst);
196 if (i > 0) {
197 bytesRead += i;
198 }
199 }
200
201 Assert.assertEquals(27, bytesRead);
202 Assert.assertEquals("123456789012345612345abcdef", CodecTestUtils.convert(dst));
203 Assert.assertTrue(decoder.isCompleted());
204
205 final List<? extends Header> trailers = decoder.getTrailers();
206 Assert.assertEquals(2, trailers.size());
207 Assert.assertEquals("Footer1", trailers.get(0).getName());
208 Assert.assertEquals("abcde", trailers.get(0).getValue());
209 Assert.assertEquals("Footer2", trailers.get(1).getName());
210 Assert.assertEquals("fghij", trailers.get(1).getValue());
211
212 dst.clear();
213 bytesRead = decoder.read(dst);
214 Assert.assertEquals(-1, bytesRead);
215 Assert.assertTrue(decoder.isCompleted());
216 }
217
218 @Test(expected=MalformedChunkCodingException.class)
219 public void testMalformedChunkSizeDecoding() throws Exception {
220 final String s = "5\r\n01234\r\n5zz\r\n56789\r\n6\r\nabcdef\r\n0\r\n\r\n";
221 final ReadableByteChannel channel = new ReadableByteChannelMock(
222 new String[] {s}, StandardCharsets.US_ASCII);
223
224 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
225 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
226 final ChunkDecoder decoder = new ChunkDecoder(channel, inbuf, metrics);
227
228 final ByteBuffer dst = ByteBuffer.allocate(1024);
229 decoder.read(dst);
230 }
231
232 @Test(expected=MalformedChunkCodingException.class)
233 public void testMalformedChunkEndingDecoding() throws Exception {
234 final String s = "5\r\n01234\r\n5\r\n56789\r\r6\r\nabcdef\r\n0\r\n\r\n";
235 final ReadableByteChannel channel = new ReadableByteChannelMock(
236 new String[] {s}, StandardCharsets.US_ASCII);
237
238 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
239 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
240 final ChunkDecoder decoder = new ChunkDecoder(channel, inbuf, metrics);
241
242 final ByteBuffer dst = ByteBuffer.allocate(1024);
243 decoder.read(dst);
244 }
245
246 @Test(expected=TruncatedChunkException.class)
247 public void testMalformedChunkTruncatedChunk() throws Exception {
248 final String s = "3\r\n12";
249 final ReadableByteChannel channel = new ReadableByteChannelMock(
250 new String[] {s}, StandardCharsets.US_ASCII);
251
252 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
253 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
254 final ChunkDecoder decoder = new ChunkDecoder(channel, inbuf, metrics);
255
256 final ByteBuffer dst = ByteBuffer.allocate(1024);
257 Assert.assertEquals(2, decoder.read(dst));
258 decoder.read(dst);
259 }
260
261 @Test
262 public void testFoldedFooters() throws Exception {
263 final String s = "10;key=\"value\"\r\n1234567890123456\r\n" +
264 "5\r\n12345\r\n5\r\n12345\r\n0\r\nFooter1: abcde\r\n \r\n fghij\r\n\r\n";
265 final ReadableByteChannel channel = new ReadableByteChannelMock(
266 new String[] {s}, StandardCharsets.US_ASCII);
267
268 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
269 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
270 final ChunkDecoder decoder = new ChunkDecoder(channel, inbuf, metrics);
271
272 final ByteBuffer dst = ByteBuffer.allocate(1024);
273
274 final int bytesRead = decoder.read(dst);
275 Assert.assertEquals(26, bytesRead);
276 Assert.assertEquals("12345678901234561234512345", CodecTestUtils.convert(dst));
277
278 final List<? extends Header> trailers = decoder.getTrailers();
279 Assert.assertEquals(1, trailers.size());
280 Assert.assertEquals("Footer1", trailers.get(0).getName());
281 Assert.assertEquals("abcde fghij", trailers.get(0).getValue());
282 }
283
284 @Test(expected=IOException.class)
285 public void testMalformedFooters() throws Exception {
286 final String s = "10;key=\"value\"\r\n1234567890123456\r\n" +
287 "5\r\n12345\r\n5\r\n12345\r\n0\r\nFooter1 abcde\r\n\r\n";
288 final ReadableByteChannel channel = new ReadableByteChannelMock(
289 new String[] {s}, StandardCharsets.US_ASCII);
290
291 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
292 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
293 final ChunkDecoder decoder = new ChunkDecoder(channel, inbuf, metrics);
294
295 final ByteBuffer dst = ByteBuffer.allocate(1024);
296 decoder.read(dst);
297 }
298
299 @Test(expected=MalformedChunkCodingException.class)
300 public void testMissingLastCRLF() throws Exception {
301 final String s = "10\r\n1234567890123456\r\n" +
302 "5\r\n12345\r\n5\r\n12345";
303 final ReadableByteChannel channel = new ReadableByteChannelMock(
304 new String[] {s}, StandardCharsets.US_ASCII);
305
306 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
307 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
308 final ChunkDecoder decoder = new ChunkDecoder(channel, inbuf, metrics);
309
310 final ByteBuffer dst = ByteBuffer.allocate(1024);
311
312 while (dst.hasRemaining() && !decoder.isCompleted()) {
313 decoder.read(dst);
314 }
315 }
316
317 @Test(expected=ConnectionClosedException.class)
318 public void testMissingClosingChunk() throws Exception {
319 final String s = "10\r\n1234567890123456\r\n" +
320 "5\r\n12345\r\n5\r\n12345\r\n";
321 final ReadableByteChannel channel = new ReadableByteChannelMock(
322 new String[] {s}, StandardCharsets.US_ASCII);
323
324 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
325 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
326 final ChunkDecoder decoder = new ChunkDecoder(channel, inbuf, metrics);
327
328 final ByteBuffer dst = ByteBuffer.allocate(1024);
329
330 long bytesRead = 0;
331 try {
332 while (dst.hasRemaining() && !decoder.isCompleted()) {
333 final int i = decoder.read(dst);
334 if (i > 0) {
335 bytesRead += i;
336 }
337 }
338 } catch (final MalformedChunkCodingException ex) {
339 Assert.assertEquals(26L, bytesRead);
340 Assert.assertEquals("12345678901234561234512345", CodecTestUtils.convert(dst));
341 Assert.assertTrue(decoder.isCompleted());
342 throw ex;
343 }
344 }
345
346 @Test
347 public void testReadingWitSmallBuffer() throws Exception {
348 final String s = "10\r\n1234567890123456\r\n" +
349 "40\r\n12345678901234561234567890123456" +
350 "12345678901234561234567890123456\r\n0\r\n";
351 final ReadableByteChannel channel = new ReadableByteChannelMock(
352 new String[] {s}, StandardCharsets.US_ASCII);
353
354 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
355 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
356 final ChunkDecoder decoder = new ChunkDecoder(channel, inbuf, metrics);
357
358 final ByteBuffer dst = ByteBuffer.allocate(1024);
359 final ByteBuffer tmp = ByteBuffer.allocate(10);
360
361 int bytesRead = 0;
362 while (dst.hasRemaining() && !decoder.isCompleted()) {
363 final int i = decoder.read(tmp);
364 if (i > 0) {
365 bytesRead += i;
366 tmp.flip();
367 dst.put(tmp);
368 tmp.compact();
369 }
370 }
371
372 Assert.assertEquals(80, bytesRead);
373 Assert.assertEquals("12345678901234561234567890123456" +
374 "12345678901234561234567890123456" +
375 "1234567890123456", CodecTestUtils.convert(dst));
376 Assert.assertTrue(decoder.isCompleted());
377 }
378
379 @Test
380 public void testEndOfStreamConditionReadingFooters() throws Exception {
381 final String s = "10\r\n1234567890123456\r\n" +
382 "5\r\n12345\r\n5\r\n12345\r\n0\r\n";
383 final ReadableByteChannel channel = new ReadableByteChannelMock(
384 new String[] {s}, StandardCharsets.US_ASCII);
385
386 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
387 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
388 final ChunkDecoder decoder = new ChunkDecoder(channel, inbuf, metrics);
389
390 final ByteBuffer dst = ByteBuffer.allocate(1024);
391
392 int bytesRead = 0;
393 while (dst.hasRemaining() && !decoder.isCompleted()) {
394 final int i = decoder.read(dst);
395 if (i > 0) {
396 bytesRead += i;
397 }
398 }
399
400 Assert.assertEquals(26, bytesRead);
401 Assert.assertEquals("12345678901234561234512345", CodecTestUtils.convert(dst));
402 Assert.assertTrue(decoder.isCompleted());
403 }
404
405 @Test
406 public void testTooLongChunkHeader() throws Exception {
407 final String s = "5; and some very looooong comment\r\n12345\r\n0\r\n";
408 final ReadableByteChannel channel1 = new ReadableByteChannelMock(
409 new String[] {s}, StandardCharsets.US_ASCII);
410
411 final BasicHttpTransportMetrics metrics1 = new BasicHttpTransportMetrics();
412 final SessionInputBuffer inbuf1 = new SessionInputBufferImpl(1024, 256);
413 final ChunkDecoder decoder1 = new ChunkDecoder(channel1, inbuf1, metrics1);
414
415 final ByteBuffer dst = ByteBuffer.allocate(1024);
416
417 while (dst.hasRemaining() && !decoder1.isCompleted()) {
418 decoder1.read(dst);
419 }
420 Assert.assertEquals("12345", CodecTestUtils.convert(dst));
421 Assert.assertTrue(decoder1.isCompleted());
422
423 final ReadableByteChannel channel2 = new ReadableByteChannelMock(
424 new String[] {s}, StandardCharsets.US_ASCII);
425
426 final SessionInputBuffer inbuf2 = new SessionInputBufferImpl(1024, 256, 10);
427 final BasicHttpTransportMetrics metrics2 = new BasicHttpTransportMetrics();
428 final ChunkDecoder decoder2 = new ChunkDecoder(channel2, inbuf2, metrics2);
429
430 dst.clear();
431 try {
432 decoder2.read(dst);
433 Assert.fail("MessageConstraintException expected");
434 } catch (final MessageConstraintException ex) {
435 }
436 }
437
438 @Test
439 public void testTooLongFooter() throws Exception {
440 final String s = "10\r\n1234567890123456\r\n" +
441 "0\r\nFooter1: looooooooooooooooooooooooooooooooooooooooooooooooooooooog\r\n\r\n";
442
443
444 final ReadableByteChannel channel1 = new ReadableByteChannelMock(
445 new String[] {s}, StandardCharsets.US_ASCII);
446 final SessionInputBuffer inbuf1 = new SessionInputBufferImpl(1024, 256, 0);
447 final BasicHttpTransportMetrics metrics1 = new BasicHttpTransportMetrics();
448 final ChunkDecoder decoder1 = new ChunkDecoder(channel1, inbuf1, metrics1);
449
450 final ByteBuffer dst = ByteBuffer.allocate(1024);
451
452 final int bytesRead = decoder1.read(dst);
453 Assert.assertEquals(16, bytesRead);
454 Assert.assertEquals("1234567890123456", CodecTestUtils.convert(dst));
455 final List<? extends Header> trailers = decoder1.getTrailers();
456 Assert.assertNotNull(trailers);
457 Assert.assertEquals(1, trailers.size());
458
459 final ReadableByteChannel channel2 = new ReadableByteChannelMock(
460 new String[] {s}, StandardCharsets.US_ASCII);
461 final SessionInputBuffer inbuf2 = new SessionInputBufferImpl(1024, 256,
462 25, StandardCharsets.US_ASCII);
463 final BasicHttpTransportMetrics metrics2 = new BasicHttpTransportMetrics();
464 final ChunkDecoder decoder2 = new ChunkDecoder(channel2, inbuf2, metrics2);
465
466 dst.clear();
467 try {
468 decoder2.read(dst);
469 Assert.fail("MessageConstraintException expected");
470 } catch (final MessageConstraintException ex) {
471 }
472 }
473
474 @Test
475 public void testTooLongFoldedFooter() throws Exception {
476 final String s = "10\r\n1234567890123456\r\n" +
477 "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";
478 final ReadableByteChannel channel1 = new ReadableByteChannelMock(
479 new String[] {s}, StandardCharsets.US_ASCII);
480 final SessionInputBuffer inbuf1 = new SessionInputBufferImpl(1024, 256,
481 0, StandardCharsets.US_ASCII);
482 final BasicHttpTransportMetrics metrics1 = new BasicHttpTransportMetrics();
483 final ChunkDecoder decoder1 = new ChunkDecoder(channel1, inbuf1, metrics1);
484
485 final ByteBuffer dst = ByteBuffer.allocate(1024);
486
487 final int bytesRead = decoder1.read(dst);
488 Assert.assertEquals(16, bytesRead);
489 Assert.assertEquals("1234567890123456", CodecTestUtils.convert(dst));
490 final List<? extends Header> trailers = decoder1.getTrailers();
491 Assert.assertNotNull(trailers);
492 Assert.assertEquals(1, trailers.size());
493
494 final Http1Config http1Config = Http1Config.custom()
495 .setMaxLineLength(25)
496 .build();
497 final ReadableByteChannel channel2 = new ReadableByteChannelMock(
498 new String[] {s}, StandardCharsets.US_ASCII);
499 final SessionInputBuffer inbuf2 = new SessionInputBufferImpl(1024, 256,0, StandardCharsets.US_ASCII);
500 final BasicHttpTransportMetrics metrics2 = new BasicHttpTransportMetrics();
501 final ChunkDecoder decoder2 = new ChunkDecoder(channel2, inbuf2, http1Config, metrics2);
502
503 dst.clear();
504 try {
505 decoder2.read(dst);
506 Assert.fail("MessageConstraintException expected");
507 } catch (final MessageConstraintException ex) {
508 }
509 }
510
511 @Test
512 public void testTooManyFooters() throws Exception {
513 final String s = "10\r\n1234567890123456\r\n" +
514 "0\r\nFooter1: blah\r\nFooter2: blah\r\nFooter3: blah\r\nFooter4: blah\r\n\r\n";
515 final ReadableByteChannel channel1 = new ReadableByteChannelMock(
516 new String[] {s}, StandardCharsets.US_ASCII);
517 final SessionInputBuffer inbuf1 = new SessionInputBufferImpl(1024, 256,0, StandardCharsets.US_ASCII);
518 final BasicHttpTransportMetrics metrics1 = new BasicHttpTransportMetrics();
519 final ChunkDecoder decoder1 = new ChunkDecoder(channel1, inbuf1, metrics1);
520
521 final ByteBuffer dst = ByteBuffer.allocate(1024);
522
523 final int bytesRead = decoder1.read(dst);
524 Assert.assertEquals(16, bytesRead);
525 Assert.assertEquals("1234567890123456", CodecTestUtils.convert(dst));
526 final List<? extends Header> trailers = decoder1.getTrailers();
527 Assert.assertNotNull(trailers);
528 Assert.assertEquals(4, trailers.size());
529
530 final Http1Config http1Config = Http1Config.custom()
531 .setMaxHeaderCount(3).build();
532 final ReadableByteChannel channel2 = new ReadableByteChannelMock(
533 new String[] {s}, StandardCharsets.US_ASCII);
534 final SessionInputBuffer inbuf2 = new SessionInputBufferImpl(1024, 256,
535 0, StandardCharsets.US_ASCII);
536 final BasicHttpTransportMetrics metrics2 = new BasicHttpTransportMetrics();
537 final ChunkDecoder decoder2 = new ChunkDecoder(channel2, inbuf2, http1Config, metrics2);
538
539 dst.clear();
540 try {
541 decoder2.read(dst);
542 Assert.fail("MessageConstraintException expected");
543 } catch (final MessageConstraintException ex) {
544 }
545 }
546
547 @Test
548 public void testInvalidConstructor() {
549 final ReadableByteChannel channel = new ReadableByteChannelMock(
550 new String[] {"stuff;", "more stuff"}, StandardCharsets.US_ASCII);
551
552 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
553 try {
554 new ChunkDecoder(null, null, null);
555 Assert.fail("NullPointerException should have been thrown");
556 } catch (final NullPointerException ex) {
557
558 }
559 try {
560 new ChunkDecoder(channel, null, null);
561 Assert.fail("NullPointerException should have been thrown");
562 } catch (final NullPointerException ex) {
563
564 }
565 try {
566 new ChunkDecoder(channel, inbuf, null);
567 Assert.fail("NullPointerException should have been thrown");
568 } catch (final NullPointerException ex) {
569
570 }
571 }
572
573 @Test(expected=NullPointerException.class)
574 public void testInvalidInput() throws Exception {
575 final String s = "10;key=\"value\"\r\n1234567890123456\r\n" +
576 "5\r\n12345\r\n5\r\n12345\r\n0\r\nFooter1 abcde\r\n\r\n";
577 final ReadableByteChannel channel = new ReadableByteChannelMock(
578 new String[] {s}, StandardCharsets.US_ASCII);
579
580 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
581 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
582 final ChunkDecoder decoder = new ChunkDecoder(channel, inbuf, metrics);
583 decoder.read(null);
584 }
585
586 @Test
587 public void testHugeChunk() throws Exception {
588 final String s = "1234567890abcdef\r\n0123456789abcdef";
589 final ReadableByteChannel channel = new ReadableByteChannelMock(new String[] {s}, StandardCharsets.US_ASCII);
590 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
591 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
592 final ChunkDecoder decoder = new ChunkDecoder(channel, inbuf, metrics);
593
594 final ByteBuffer dst = ByteBuffer.allocate(4);
595
596 int bytesRead = decoder.read(dst);
597 Assert.assertEquals(4, bytesRead);
598 Assert.assertEquals("0123", CodecTestUtils.convert(dst));
599 dst.clear();
600 bytesRead = decoder.read(dst);
601 Assert.assertEquals(4, bytesRead);
602 Assert.assertEquals("4567", CodecTestUtils.convert(dst));
603 }
604
605 }