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.After;
43  import org.junit.Assert;
44  import org.junit.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      @After
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          Assert.assertEquals(6, bytesRead);
79          Assert.assertEquals("stuff;", CodecTestUtils.convert(dst));
80          Assert.assertFalse(decoder.isCompleted());
81          Assert.assertEquals(6, metrics.getBytesTransferred());
82  
83          dst.clear();
84          bytesRead = decoder.read(dst);
85          Assert.assertEquals(10, bytesRead);
86          Assert.assertEquals("more stuff", CodecTestUtils.convert(dst));
87          Assert.assertTrue(decoder.isCompleted());
88          Assert.assertEquals(16, metrics.getBytesTransferred());
89  
90          dst.clear();
91          bytesRead = decoder.read(dst);
92          Assert.assertEquals(-1, bytesRead);
93          Assert.assertTrue(decoder.isCompleted());
94          Assert.assertEquals(16, metrics.getBytesTransferred());
95  
96          Assert.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         Assert.assertEquals(6, bytesRead);
115         Assert.assertEquals("stuff;", CodecTestUtils.convert(dst));
116         Assert.assertFalse(decoder.isCompleted());
117         Assert.assertEquals(6, metrics.getBytesTransferred());
118 
119         dst.clear();
120         bytesRead = decoder.read(dst);
121         Assert.assertEquals(10, bytesRead);
122         Assert.assertEquals("more stuff", CodecTestUtils.convert(dst));
123         Assert.assertTrue(decoder.isCompleted());
124         Assert.assertEquals(16, metrics.getBytesTransferred());
125 
126         dst.clear();
127         bytesRead = decoder.read(dst);
128         Assert.assertEquals(-1, bytesRead);
129         Assert.assertTrue(decoder.isCompleted());
130         Assert.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         Assert.assertEquals(4, bytesRead);
147         Assert.assertEquals("stuf", CodecTestUtils.convert(dst));
148         Assert.assertFalse(decoder.isCompleted());
149         Assert.assertEquals(4, metrics.getBytesTransferred());
150 
151         dst.clear();
152         bytesRead = decoder.read(dst);
153         Assert.assertEquals(2, bytesRead);
154         Assert.assertEquals("f;", CodecTestUtils.convert(dst));
155         Assert.assertFalse(decoder.isCompleted());
156         Assert.assertEquals(6, metrics.getBytesTransferred());
157 
158         dst.clear();
159         bytesRead = decoder.read(dst);
160         Assert.assertEquals(4, bytesRead);
161         Assert.assertEquals("more", CodecTestUtils.convert(dst));
162         Assert.assertFalse(decoder.isCompleted());
163         Assert.assertEquals(10, metrics.getBytesTransferred());
164 
165         dst.clear();
166         bytesRead = decoder.read(dst);
167         Assert.assertEquals(4, bytesRead);
168         Assert.assertEquals(" stu", CodecTestUtils.convert(dst));
169         Assert.assertFalse(decoder.isCompleted());
170         Assert.assertEquals(14, metrics.getBytesTransferred());
171 
172         dst.clear();
173         bytesRead = decoder.read(dst);
174         Assert.assertEquals(2, bytesRead);
175         Assert.assertEquals("ff", CodecTestUtils.convert(dst));
176         Assert.assertTrue(decoder.isCompleted());
177         Assert.assertEquals(16, metrics.getBytesTransferred());
178 
179         dst.clear();
180         bytesRead = decoder.read(dst);
181         Assert.assertEquals(-1, bytesRead);
182         Assert.assertTrue(decoder.isCompleted());
183         Assert.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         Assert.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         Assert.assertEquals(6, bytesRead);
205         Assert.assertEquals("stuff;", CodecTestUtils.convert(dst));
206         Assert.assertFalse(decoder.isCompleted());
207         Assert.assertEquals(0, metrics.getBytesTransferred());
208 
209         dst.clear();
210         bytesRead = decoder.read(dst);
211         Assert.assertEquals(10, bytesRead);
212         Assert.assertEquals("more stuff", CodecTestUtils.convert(dst));
213         Assert.assertTrue(decoder.isCompleted());
214         Assert.assertEquals(10, metrics.getBytesTransferred());
215 
216         dst.clear();
217         bytesRead = decoder.read(dst);
218         Assert.assertEquals(-1, bytesRead);
219         Assert.assertTrue(decoder.isCompleted());
220         Assert.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         Assert.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         Assert.assertEquals(16, bytesRead);
245         Assert.assertEquals("stuff;more stuff", CodecTestUtils.convert(dst));
246         Assert.assertTrue(decoder.isCompleted());
247         Assert.assertEquals(0, metrics.getBytesTransferred());
248 
249         dst.clear();
250         bytesRead = decoder.read(dst);
251         Assert.assertEquals(-1, bytesRead);
252         Assert.assertTrue(decoder.isCompleted());
253         Assert.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         Assert.assertEquals(this.tmpfile.length(), metrics.getBytesTransferred());
279         Assert.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         Assert.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         Assert.assertEquals(this.tmpfile.length() - 7, metrics.getBytesTransferred());
308         Assert.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         Assert.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         Assert.assertEquals(this.tmpfile.length() - 7 - beginning.length, metrics.getBytesTransferred());
355         Assert.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         Assert.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             Assert.assertEquals(1, bytesRead);
379             Assert.assertFalse(decoder.isCompleted());
380             Assert.assertEquals(0, metrics.getBytesTransferred());
381             pos += bytesRead;
382 
383             bytesRead = decoder.transfer(fchannel, pos, 2);
384             Assert.assertEquals(2, bytesRead);
385             Assert.assertFalse(decoder.isCompleted());
386             Assert.assertEquals(0, metrics.getBytesTransferred());
387             pos += bytesRead;
388 
389             bytesRead = decoder.transfer(fchannel, pos, 17);
390             Assert.assertEquals(16, bytesRead);
391             Assert.assertFalse(decoder.isCompleted());
392             Assert.assertEquals(0, metrics.getBytesTransferred());
393             pos += bytesRead;
394 
395             // transferred from channel
396             bytesRead = decoder.transfer(fchannel, pos, 1);
397             Assert.assertEquals(1, bytesRead);
398             Assert.assertFalse(decoder.isCompleted());
399             Assert.assertEquals(1, metrics.getBytesTransferred());
400             pos += bytesRead;
401 
402             bytesRead = decoder.transfer(fchannel, pos, 2);
403             Assert.assertEquals(2, bytesRead);
404             Assert.assertFalse(decoder.isCompleted());
405             Assert.assertEquals(3, metrics.getBytesTransferred());
406             pos += bytesRead;
407 
408             bytesRead = decoder.transfer(fchannel, pos, 15);
409             Assert.assertEquals(14, bytesRead);
410             Assert.assertTrue(decoder.isCompleted());
411             Assert.assertEquals(17, metrics.getBytesTransferred());
412             pos += bytesRead;
413 
414             bytesRead = decoder.transfer(fchannel, pos, 1);
415             Assert.assertEquals(-1, bytesRead);
416             Assert.assertTrue(decoder.isCompleted());
417             Assert.assertEquals(17, metrics.getBytesTransferred());
418         }
419         Assert.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             Assert.assertEquals(0, testfile.length());
437             try {
438                 decoder.transfer(fchannel, 5, 10);
439                 Assert.fail("IOException should have been thrown");
440             } catch(final IOException expected) {
441             }
442         }
443     }
444 
445     @Test
446     public void testCodingBeyondContentLimitFile() throws Exception {
447         final ReadableByteChannel channel = new ReadableByteChannelMock(
448                 new String[] {
449                         "stuff;",
450                         "more stuff; and a lot more stuff"}, StandardCharsets.US_ASCII);
451 
452         final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
453         final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
454         final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder(
455                 channel, inbuf, metrics, 16);
456 
457         createTempFile();
458         try (RandomAccessFile testfile  = new RandomAccessFile(this.tmpfile, "rw")) {
459             final FileChannel fchannel = testfile.getChannel();
460 
461             long bytesRead = decoder.transfer(fchannel, 0, 6);
462             Assert.assertEquals(6, bytesRead);
463             Assert.assertFalse(decoder.isCompleted());
464             Assert.assertEquals(6, metrics.getBytesTransferred());
465 
466             bytesRead = decoder.transfer(fchannel,0 , 10);
467             Assert.assertEquals(10, bytesRead);
468             Assert.assertTrue(decoder.isCompleted());
469             Assert.assertEquals(16, metrics.getBytesTransferred());
470 
471             bytesRead = decoder.transfer(fchannel, 0, 1);
472             Assert.assertEquals(-1, bytesRead);
473             Assert.assertTrue(decoder.isCompleted());
474             Assert.assertEquals(16, metrics.getBytesTransferred());
475         }
476     }
477 
478     @Test
479     public void testInvalidConstructor() {
480         final ReadableByteChannel channel = new ReadableByteChannelMock(
481                 new String[] {"stuff;", "more stuff"}, StandardCharsets.US_ASCII);
482 
483         final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
484         final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
485         try {
486             new LengthDelimitedDecoder(null, null, null, 10);
487             Assert.fail("NullPointerException should have been thrown");
488         } catch (final NullPointerException ex) {
489             // ignore
490         }
491         try {
492             new LengthDelimitedDecoder(channel, null, null, 10);
493             Assert.fail("NullPointerException should have been thrown");
494         } catch (final NullPointerException ex) {
495             // ignore
496         }
497         try {
498             new LengthDelimitedDecoder(channel, inbuf, null, 10);
499             Assert.fail("NullPointerException should have been thrown");
500         } catch (final NullPointerException ex) {
501             // ignore
502         }
503         try {
504             new LengthDelimitedDecoder(channel, inbuf, metrics, -10);
505             Assert.fail("IllegalArgumentException should have been thrown");
506         } catch (final IllegalArgumentException ex) {
507             // ignore
508         }
509     }
510 
511     @Test
512     public void testInvalidInput() throws Exception {
513         final String s = "stuff";
514         final ReadableByteChannel channel = new ReadableByteChannelMock(
515                 new String[] {s}, StandardCharsets.US_ASCII);
516 
517         final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
518         final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
519         final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder(
520                 channel, inbuf, metrics, 3);
521 
522         try {
523             decoder.read(null);
524             Assert.fail("NullPointerException should have been thrown");
525         } catch (final NullPointerException ex) {
526             // expected
527         }
528     }
529 
530     @Test
531     public void testZeroLengthDecoding() throws Exception {
532         final ReadableByteChannel channel = new ReadableByteChannelMock(
533                 new String[] {"stuff"}, StandardCharsets.US_ASCII);
534 
535         final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
536         final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
537         final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder(
538                 channel, inbuf, metrics, 0);
539 
540         final ByteBuffer dst = ByteBuffer.allocate(1024);
541 
542         final int bytesRead = decoder.read(dst);
543         Assert.assertEquals(-1, bytesRead);
544         Assert.assertTrue(decoder.isCompleted());
545         Assert.assertEquals(0, metrics.getBytesTransferred());
546     }
547 
548     @Test(expected=ConnectionClosedException.class)
549     public void testTruncatedContent() throws Exception {
550         final ReadableByteChannel channel = new ReadableByteChannelMock(
551                 new String[] {"1234567890"}, StandardCharsets.US_ASCII);
552 
553         final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
554         final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
555         final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder(
556                 channel, inbuf, metrics, 20);
557 
558         final ByteBuffer dst = ByteBuffer.allocate(1024);
559 
560         final int bytesRead = decoder.read(dst);
561         Assert.assertEquals(10, bytesRead);
562         decoder.read(dst);
563     }
564 
565     @Test(expected=ConnectionClosedException.class)
566     public void testTruncatedContentWithFile() throws Exception {
567         final ReadableByteChannel channel = new ReadableByteChannelMock(
568                 new String[] {"1234567890"}, StandardCharsets.US_ASCII);
569 
570         final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
571         final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
572         final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder(
573                 channel, inbuf, metrics, 20);
574 
575         createTempFile();
576         try (RandomAccessFile testfile  = new RandomAccessFile(this.tmpfile, "rw")) {
577             final FileChannel fchannel = testfile.getChannel();
578             final long bytesRead = decoder.transfer(fchannel, 0, Integer.MAX_VALUE);
579             Assert.assertEquals(10, bytesRead);
580             decoder.transfer(fchannel, 0, Integer.MAX_VALUE);
581         }
582     }
583 
584 }