View Javadoc
1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  
28  package org.apache.hc.core5.http.impl.nio;
29  
30  import java.io.File;
31  import java.io.IOException;
32  import java.io.RandomAccessFile;
33  import java.nio.ByteBuffer;
34  import java.nio.channels.FileChannel;
35  import java.nio.channels.ReadableByteChannel;
36  import java.nio.charset.StandardCharsets;
37  
38  import org.apache.hc.core5.http.ConnectionClosedException;
39  import org.apache.hc.core5.http.ReadableByteChannelMock;
40  import org.apache.hc.core5.http.impl.BasicHttpTransportMetrics;
41  import org.apache.hc.core5.http.nio.SessionInputBuffer;
42  import org.junit.jupiter.api.AfterEach;
43  import org.junit.jupiter.api.Assertions;
44  import org.junit.jupiter.api.Test;
45  
46  /**
47   * Simple tests for {@link LengthDelimitedDecoder}.
48   */
49  public class TestLengthDelimitedDecoder {
50  
51      private File tmpfile;
52  
53      protected File createTempFile() throws IOException {
54          this.tmpfile = File.createTempFile("testFile", ".txt");
55          return this.tmpfile;
56      }
57  
58      @AfterEach
59      public void deleteTempFile() {
60          if (this.tmpfile != null && this.tmpfile.exists()) {
61              this.tmpfile.delete();
62          }
63      }
64  
65      @Test
66      public void testBasicDecoding() throws Exception {
67          final ReadableByteChannel channel = new ReadableByteChannelMock(
68                  new String[] {"stuff;", "more stuff"}, StandardCharsets.US_ASCII);
69  
70          final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
71          final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
72          final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder(
73                  channel, inbuf, metrics, 16);
74  
75          final ByteBuffer dst = ByteBuffer.allocate(1024);
76  
77          int bytesRead = decoder.read(dst);
78          Assertions.assertEquals(6, bytesRead);
79          Assertions.assertEquals("stuff;", CodecTestUtils.convert(dst));
80          Assertions.assertFalse(decoder.isCompleted());
81          Assertions.assertEquals(6, metrics.getBytesTransferred());
82  
83          dst.clear();
84          bytesRead = decoder.read(dst);
85          Assertions.assertEquals(10, bytesRead);
86          Assertions.assertEquals("more stuff", CodecTestUtils.convert(dst));
87          Assertions.assertTrue(decoder.isCompleted());
88          Assertions.assertEquals(16, metrics.getBytesTransferred());
89  
90          dst.clear();
91          bytesRead = decoder.read(dst);
92          Assertions.assertEquals(-1, bytesRead);
93          Assertions.assertTrue(decoder.isCompleted());
94          Assertions.assertEquals(16, metrics.getBytesTransferred());
95  
96          Assertions.assertEquals("[content length: 16; pos: 16; completed: true]", decoder.toString());
97      }
98  
99      @Test
100     public void testCodingBeyondContentLimit() throws Exception {
101         final ReadableByteChannel channel = new ReadableByteChannelMock(
102                 new String[] {
103                         "stuff;",
104                         "more stuff; and a lot more stuff"}, StandardCharsets.US_ASCII);
105 
106         final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
107         final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
108         final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder(
109                 channel, inbuf, metrics, 16);
110 
111         final ByteBuffer dst = ByteBuffer.allocate(1024);
112 
113         int bytesRead = decoder.read(dst);
114         Assertions.assertEquals(6, bytesRead);
115         Assertions.assertEquals("stuff;", CodecTestUtils.convert(dst));
116         Assertions.assertFalse(decoder.isCompleted());
117         Assertions.assertEquals(6, metrics.getBytesTransferred());
118 
119         dst.clear();
120         bytesRead = decoder.read(dst);
121         Assertions.assertEquals(10, bytesRead);
122         Assertions.assertEquals("more stuff", CodecTestUtils.convert(dst));
123         Assertions.assertTrue(decoder.isCompleted());
124         Assertions.assertEquals(16, metrics.getBytesTransferred());
125 
126         dst.clear();
127         bytesRead = decoder.read(dst);
128         Assertions.assertEquals(-1, bytesRead);
129         Assertions.assertTrue(decoder.isCompleted());
130         Assertions.assertEquals(16, metrics.getBytesTransferred());
131     }
132 
133     @Test
134     public void testBasicDecodingSmallBuffer() throws Exception {
135         final ReadableByteChannel channel = new ReadableByteChannelMock(
136                 new String[] {"stuff;", "more stuff"}, StandardCharsets.US_ASCII);
137 
138         final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
139         final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
140         final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder(
141                 channel, inbuf, metrics, 16);
142 
143         final ByteBuffer dst = ByteBuffer.allocate(4);
144 
145         int bytesRead = decoder.read(dst);
146         Assertions.assertEquals(4, bytesRead);
147         Assertions.assertEquals("stuf", CodecTestUtils.convert(dst));
148         Assertions.assertFalse(decoder.isCompleted());
149         Assertions.assertEquals(4, metrics.getBytesTransferred());
150 
151         dst.clear();
152         bytesRead = decoder.read(dst);
153         Assertions.assertEquals(2, bytesRead);
154         Assertions.assertEquals("f;", CodecTestUtils.convert(dst));
155         Assertions.assertFalse(decoder.isCompleted());
156         Assertions.assertEquals(6, metrics.getBytesTransferred());
157 
158         dst.clear();
159         bytesRead = decoder.read(dst);
160         Assertions.assertEquals(4, bytesRead);
161         Assertions.assertEquals("more", CodecTestUtils.convert(dst));
162         Assertions.assertFalse(decoder.isCompleted());
163         Assertions.assertEquals(10, metrics.getBytesTransferred());
164 
165         dst.clear();
166         bytesRead = decoder.read(dst);
167         Assertions.assertEquals(4, bytesRead);
168         Assertions.assertEquals(" stu", CodecTestUtils.convert(dst));
169         Assertions.assertFalse(decoder.isCompleted());
170         Assertions.assertEquals(14, metrics.getBytesTransferred());
171 
172         dst.clear();
173         bytesRead = decoder.read(dst);
174         Assertions.assertEquals(2, bytesRead);
175         Assertions.assertEquals("ff", CodecTestUtils.convert(dst));
176         Assertions.assertTrue(decoder.isCompleted());
177         Assertions.assertEquals(16, metrics.getBytesTransferred());
178 
179         dst.clear();
180         bytesRead = decoder.read(dst);
181         Assertions.assertEquals(-1, bytesRead);
182         Assertions.assertTrue(decoder.isCompleted());
183         Assertions.assertEquals(16, metrics.getBytesTransferred());
184     }
185 
186     @Test
187     public void testDecodingFromSessionBuffer1() throws Exception {
188         final ReadableByteChannel channel = new ReadableByteChannelMock(
189                 new String[] {"stuff;", "more stuff"}, StandardCharsets.US_ASCII);
190 
191         final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
192         final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
193 
194         inbuf.fill(channel);
195 
196         Assertions.assertEquals(6, inbuf.length());
197 
198         final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder(
199                 channel, inbuf, metrics, 16);
200 
201         final ByteBuffer dst = ByteBuffer.allocate(1024);
202 
203         int bytesRead = decoder.read(dst);
204         Assertions.assertEquals(6, bytesRead);
205         Assertions.assertEquals("stuff;", CodecTestUtils.convert(dst));
206         Assertions.assertFalse(decoder.isCompleted());
207         Assertions.assertEquals(0, metrics.getBytesTransferred());
208 
209         dst.clear();
210         bytesRead = decoder.read(dst);
211         Assertions.assertEquals(10, bytesRead);
212         Assertions.assertEquals("more stuff", CodecTestUtils.convert(dst));
213         Assertions.assertTrue(decoder.isCompleted());
214         Assertions.assertEquals(10, metrics.getBytesTransferred());
215 
216         dst.clear();
217         bytesRead = decoder.read(dst);
218         Assertions.assertEquals(-1, bytesRead);
219         Assertions.assertTrue(decoder.isCompleted());
220         Assertions.assertEquals(10, metrics.getBytesTransferred());
221     }
222 
223     @Test
224     public void testDecodingFromSessionBuffer2() throws Exception {
225         final ReadableByteChannel channel = new ReadableByteChannelMock(
226                 new String[] {
227                         "stuff;",
228                         "more stuff; and a lot more stuff"}, StandardCharsets.US_ASCII);
229 
230         final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
231         final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
232 
233         inbuf.fill(channel);
234         inbuf.fill(channel);
235 
236         Assertions.assertEquals(38, inbuf.length());
237 
238         final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder(
239                 channel, inbuf, metrics, 16);
240 
241         final ByteBuffer dst = ByteBuffer.allocate(1024);
242 
243         int bytesRead = decoder.read(dst);
244         Assertions.assertEquals(16, bytesRead);
245         Assertions.assertEquals("stuff;more stuff", CodecTestUtils.convert(dst));
246         Assertions.assertTrue(decoder.isCompleted());
247         Assertions.assertEquals(0, metrics.getBytesTransferred());
248 
249         dst.clear();
250         bytesRead = decoder.read(dst);
251         Assertions.assertEquals(-1, bytesRead);
252         Assertions.assertTrue(decoder.isCompleted());
253         Assertions.assertEquals(0, metrics.getBytesTransferred());
254     }
255 
256     /* ----------------- FileChannel Part testing --------------------------- */
257     @Test
258     public void testBasicDecodingFile() throws Exception {
259         final ReadableByteChannel channel = new ReadableByteChannelMock(
260                 new String[] {"stuff; ", "more stuff; ", "a lot more stuff!!!"}, StandardCharsets.US_ASCII);
261 
262         final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
263         final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
264         final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder(
265                 channel, inbuf, metrics, 36);
266 
267         createTempFile();
268         try (RandomAccessFile testfile = new RandomAccessFile(this.tmpfile, "rw")) {
269             final FileChannel fchannel = testfile.getChannel();
270             long pos = 0;
271             while (!decoder.isCompleted()) {
272                 final long bytesRead = decoder.transfer(fchannel, pos, 10);
273                 if (bytesRead > 0) {
274                     pos += bytesRead;
275                 }
276             }
277         }
278         Assertions.assertEquals(this.tmpfile.length(), metrics.getBytesTransferred());
279         Assertions.assertEquals("stuff; more stuff; a lot more stuff!",
280             CodecTestUtils.readFromFile(this.tmpfile));
281     }
282 
283     @Test
284     public void testDecodingFileWithBufferedSessionData() throws Exception {
285         final ReadableByteChannel channel = new ReadableByteChannelMock(
286                 new String[] {"stuff; ", "more stuff; ", "a lot more stuff!!!"}, StandardCharsets.US_ASCII);
287 
288         final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
289         final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
290         final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder(
291                 channel, inbuf, metrics, 36);
292 
293         final int i = inbuf.fill(channel);
294         Assertions.assertEquals(7, i);
295 
296         createTempFile();
297         try (RandomAccessFile testfile = new RandomAccessFile(this.tmpfile, "rw")) {
298             final FileChannel fchannel = testfile.getChannel();
299             long pos = 0;
300             while (!decoder.isCompleted()) {
301                 final long bytesRead = decoder.transfer(fchannel, pos, 10);
302                 if (bytesRead > 0) {
303                     pos += bytesRead;
304                 }
305             }
306         }
307         Assertions.assertEquals(this.tmpfile.length() - 7, metrics.getBytesTransferred());
308         Assertions.assertEquals("stuff; more stuff; a lot more stuff!",
309             CodecTestUtils.readFromFile(this.tmpfile));
310     }
311 
312     @Test
313     public void testDecodingFileWithOffsetAndBufferedSessionData() throws Exception {
314         final ReadableByteChannel channel = new ReadableByteChannelMock(
315                 new String[] {"stuff; ", "more stuff; ", "a lot more stuff!"}, StandardCharsets.US_ASCII);
316 
317         final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
318         final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
319         final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder(
320                 channel, inbuf, metrics, 36);
321 
322         final int i = inbuf.fill(channel);
323         Assertions.assertEquals(7, i);
324 
325         final byte[] beginning =  "beginning; ".getBytes(StandardCharsets.US_ASCII);
326 
327         createTempFile();
328         RandomAccessFile testfile = new RandomAccessFile(this.tmpfile, "rw");
329         try {
330             testfile.write(beginning);
331         } finally {
332             testfile.close();
333         }
334 
335         testfile = new RandomAccessFile(this.tmpfile, "rw");
336         try {
337             final FileChannel fchannel = testfile.getChannel();
338 
339             long pos = beginning.length;
340             while (!decoder.isCompleted()) {
341                 if(testfile.length() < pos) {
342                     testfile.setLength(pos);
343                 }
344                 final long bytesRead = decoder.transfer(fchannel, pos, 10);
345                 if (bytesRead > 0) {
346                     pos += bytesRead;
347                 }
348             }
349         } finally {
350             testfile.close();
351         }
352 
353         // count everything except the initial 7 bytes that went to the session buffer
354         Assertions.assertEquals(this.tmpfile.length() - 7 - beginning.length, metrics.getBytesTransferred());
355         Assertions.assertEquals("beginning; stuff; more stuff; a lot more stuff!",
356             CodecTestUtils.readFromFile(this.tmpfile));
357     }
358 
359     @Test
360     public void testDecodingFileWithLimit() throws Exception {
361         final ReadableByteChannel channel = new ReadableByteChannelMock(
362                 new String[] {"stuff; more stuff; ", "a lot more stuff!!!"}, StandardCharsets.US_ASCII);
363 
364         final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
365         final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
366         final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder(channel, inbuf, metrics, 36);
367 
368         final int i = inbuf.fill(channel);
369         Assertions.assertEquals(19, i);
370 
371         createTempFile();
372         try (RandomAccessFile testfile = new RandomAccessFile(this.tmpfile, "rw")) {
373             final FileChannel fchannel = testfile.getChannel();
374             long pos = 0;
375 
376             // transferred from buffer
377             long bytesRead = decoder.transfer(fchannel, pos, 1);
378             Assertions.assertEquals(1, bytesRead);
379             Assertions.assertFalse(decoder.isCompleted());
380             Assertions.assertEquals(0, metrics.getBytesTransferred());
381             pos += bytesRead;
382 
383             bytesRead = decoder.transfer(fchannel, pos, 2);
384             Assertions.assertEquals(2, bytesRead);
385             Assertions.assertFalse(decoder.isCompleted());
386             Assertions.assertEquals(0, metrics.getBytesTransferred());
387             pos += bytesRead;
388 
389             bytesRead = decoder.transfer(fchannel, pos, 17);
390             Assertions.assertEquals(16, bytesRead);
391             Assertions.assertFalse(decoder.isCompleted());
392             Assertions.assertEquals(0, metrics.getBytesTransferred());
393             pos += bytesRead;
394 
395             // transferred from channel
396             bytesRead = decoder.transfer(fchannel, pos, 1);
397             Assertions.assertEquals(1, bytesRead);
398             Assertions.assertFalse(decoder.isCompleted());
399             Assertions.assertEquals(1, metrics.getBytesTransferred());
400             pos += bytesRead;
401 
402             bytesRead = decoder.transfer(fchannel, pos, 2);
403             Assertions.assertEquals(2, bytesRead);
404             Assertions.assertFalse(decoder.isCompleted());
405             Assertions.assertEquals(3, metrics.getBytesTransferred());
406             pos += bytesRead;
407 
408             bytesRead = decoder.transfer(fchannel, pos, 15);
409             Assertions.assertEquals(14, bytesRead);
410             Assertions.assertTrue(decoder.isCompleted());
411             Assertions.assertEquals(17, metrics.getBytesTransferred());
412             pos += bytesRead;
413 
414             bytesRead = decoder.transfer(fchannel, pos, 1);
415             Assertions.assertEquals(-1, bytesRead);
416             Assertions.assertTrue(decoder.isCompleted());
417             Assertions.assertEquals(17, metrics.getBytesTransferred());
418         }
419         Assertions.assertEquals("stuff; more stuff; a lot more stuff!",
420                 CodecTestUtils.readFromFile(this.tmpfile));
421     }
422 
423     @Test
424     public void testWriteBeyondFileSize() throws Exception {
425         final ReadableByteChannel channel = new ReadableByteChannelMock(
426                 new String[] {"a"}, StandardCharsets.US_ASCII);
427 
428         final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
429         final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
430         final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder(
431                 channel, inbuf, metrics, 1);
432 
433         createTempFile();
434         try (RandomAccessFile testfile = new RandomAccessFile(this.tmpfile, "rw")) {
435             final FileChannel fchannel = testfile.getChannel();
436             Assertions.assertEquals(0, testfile.length());
437             Assertions.assertThrows(IOException.class, () -> decoder.transfer(fchannel, 5, 10));
438         }
439     }
440 
441     @Test
442     public void testCodingBeyondContentLimitFile() throws Exception {
443         final ReadableByteChannel channel = new ReadableByteChannelMock(
444                 new String[] {
445                         "stuff;",
446                         "more stuff; and a lot more stuff"}, StandardCharsets.US_ASCII);
447 
448         final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
449         final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
450         final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder(
451                 channel, inbuf, metrics, 16);
452 
453         createTempFile();
454         try (RandomAccessFile testfile  = new RandomAccessFile(this.tmpfile, "rw")) {
455             final FileChannel fchannel = testfile.getChannel();
456 
457             long bytesRead = decoder.transfer(fchannel, 0, 6);
458             Assertions.assertEquals(6, bytesRead);
459             Assertions.assertFalse(decoder.isCompleted());
460             Assertions.assertEquals(6, metrics.getBytesTransferred());
461 
462             bytesRead = decoder.transfer(fchannel,0 , 10);
463             Assertions.assertEquals(10, bytesRead);
464             Assertions.assertTrue(decoder.isCompleted());
465             Assertions.assertEquals(16, metrics.getBytesTransferred());
466 
467             bytesRead = decoder.transfer(fchannel, 0, 1);
468             Assertions.assertEquals(-1, bytesRead);
469             Assertions.assertTrue(decoder.isCompleted());
470             Assertions.assertEquals(16, metrics.getBytesTransferred());
471         }
472     }
473 
474     @Test
475     public void testInvalidConstructor() {
476         final ReadableByteChannel channel = new ReadableByteChannelMock(
477                 new String[] {"stuff;", "more stuff"}, StandardCharsets.US_ASCII);
478 
479         final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
480         final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
481         Assertions.assertThrows(NullPointerException.class, () -> new LengthDelimitedDecoder(null, null, null, 10));
482         Assertions.assertThrows(NullPointerException.class, () -> new LengthDelimitedDecoder(channel, null, null, 10));
483         Assertions.assertThrows(NullPointerException.class, () -> new LengthDelimitedDecoder(channel, inbuf, null, 10));
484         Assertions.assertThrows(IllegalArgumentException.class, () -> new LengthDelimitedDecoder(channel, inbuf, metrics, -10));
485     }
486 
487     @Test
488     public void testInvalidInput() throws Exception {
489         final String s = "stuff";
490         final ReadableByteChannel channel = new ReadableByteChannelMock(
491                 new String[] {s}, StandardCharsets.US_ASCII);
492 
493         final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
494         final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
495         final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder(
496                 channel, inbuf, metrics, 3);
497 
498         Assertions.assertThrows(NullPointerException.class, () -> decoder.read(null));
499     }
500 
501     @Test
502     public void testZeroLengthDecoding() throws Exception {
503         final ReadableByteChannel channel = new ReadableByteChannelMock(
504                 new String[] {"stuff"}, StandardCharsets.US_ASCII);
505 
506         final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
507         final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
508         final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder(
509                 channel, inbuf, metrics, 0);
510 
511         final ByteBuffer dst = ByteBuffer.allocate(1024);
512 
513         final int bytesRead = decoder.read(dst);
514         Assertions.assertEquals(-1, bytesRead);
515         Assertions.assertTrue(decoder.isCompleted());
516         Assertions.assertEquals(0, metrics.getBytesTransferred());
517     }
518 
519     @Test
520     public void testTruncatedContent() throws Exception {
521         final ReadableByteChannel channel = new ReadableByteChannelMock(
522                 new String[] {"1234567890"}, StandardCharsets.US_ASCII);
523 
524         final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
525         final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
526         final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder(
527                 channel, inbuf, metrics, 20);
528 
529         final ByteBuffer dst = ByteBuffer.allocate(1024);
530 
531         final int bytesRead = decoder.read(dst);
532         Assertions.assertEquals(10, bytesRead);
533         Assertions.assertThrows(ConnectionClosedException.class, () ->
534                 decoder.read(dst));
535     }
536 
537     @Test
538     public void testTruncatedContentWithFile() throws Exception {
539         final ReadableByteChannel channel = new ReadableByteChannelMock(
540                 new String[] {"1234567890"}, StandardCharsets.US_ASCII);
541 
542         final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
543         final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
544         final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder(
545                 channel, inbuf, metrics, 20);
546 
547         createTempFile();
548         try (RandomAccessFile testfile  = new RandomAccessFile(this.tmpfile, "rw")) {
549             final FileChannel fchannel = testfile.getChannel();
550             final long bytesRead = decoder.transfer(fchannel, 0, Integer.MAX_VALUE);
551             Assertions.assertEquals(10, bytesRead);
552             Assertions.assertThrows(ConnectionClosedException.class, () ->
553                     decoder.transfer(fchannel, 0, Integer.MAX_VALUE));
554         }
555     }
556 
557 }