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.http.impl.nio.codecs;
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
37 import org.apache.http.ConnectionClosedException;
38 import org.apache.http.Consts;
39 import org.apache.http.ReadableByteChannelMock;
40 import org.apache.http.impl.io.HttpTransportMetricsImpl;
41 import org.apache.http.impl.nio.reactor.SessionInputBufferImpl;
42 import org.apache.http.nio.reactor.SessionInputBuffer;
43 import org.apache.http.util.EncodingUtils;
44 import org.junit.After;
45 import org.junit.Assert;
46 import org.junit.Test;
47
48
49
50
51 public class TestLengthDelimitedDecoder {
52
53 private File tmpfile;
54
55 protected File createTempFile() throws IOException {
56 this.tmpfile = File.createTempFile("testFile", ".txt");
57 return this.tmpfile;
58 }
59
60 @After
61 public void deleteTempFile() {
62 if (this.tmpfile != null && this.tmpfile.exists()) {
63 this.tmpfile.delete();
64 }
65 }
66
67 @Test
68 public void testBasicDecoding() throws Exception {
69 final ReadableByteChannel channel = new ReadableByteChannelMock(
70 new String[] {"stuff;", "more stuff"}, Consts.ASCII);
71
72 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, Consts.ASCII);
73 final HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl();
74 final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder(
75 channel, inbuf, metrics, 16);
76
77 final ByteBuffer dst = ByteBuffer.allocate(1024);
78
79 int bytesRead = decoder.read(dst);
80 Assert.assertEquals(6, bytesRead);
81 Assert.assertEquals("stuff;", CodecTestUtils.convert(dst));
82 Assert.assertFalse(decoder.isCompleted());
83 Assert.assertEquals(6, metrics.getBytesTransferred());
84
85 dst.clear();
86 bytesRead = decoder.read(dst);
87 Assert.assertEquals(10, bytesRead);
88 Assert.assertEquals("more stuff", CodecTestUtils.convert(dst));
89 Assert.assertTrue(decoder.isCompleted());
90 Assert.assertEquals(16, metrics.getBytesTransferred());
91
92 dst.clear();
93 bytesRead = decoder.read(dst);
94 Assert.assertEquals(-1, bytesRead);
95 Assert.assertTrue(decoder.isCompleted());
96 Assert.assertEquals(16, metrics.getBytesTransferred());
97
98 Assert.assertEquals("[content length: 16; pos: 16; completed: true]", decoder.toString());
99 }
100
101 @Test
102 public void testCodingBeyondContentLimit() throws Exception {
103 final ReadableByteChannel channel = new ReadableByteChannelMock(
104 new String[] {
105 "stuff;",
106 "more stuff; and a lot more stuff"}, Consts.ASCII);
107
108 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, Consts.ASCII);
109 final HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl();
110 final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder(
111 channel, inbuf, metrics, 16);
112
113 final ByteBuffer dst = ByteBuffer.allocate(1024);
114
115 int bytesRead = decoder.read(dst);
116 Assert.assertEquals(6, bytesRead);
117 Assert.assertEquals("stuff;", CodecTestUtils.convert(dst));
118 Assert.assertFalse(decoder.isCompleted());
119 Assert.assertEquals(6, metrics.getBytesTransferred());
120
121 dst.clear();
122 bytesRead = decoder.read(dst);
123 Assert.assertEquals(10, bytesRead);
124 Assert.assertEquals("more stuff", CodecTestUtils.convert(dst));
125 Assert.assertTrue(decoder.isCompleted());
126 Assert.assertEquals(16, metrics.getBytesTransferred());
127
128 dst.clear();
129 bytesRead = decoder.read(dst);
130 Assert.assertEquals(-1, bytesRead);
131 Assert.assertTrue(decoder.isCompleted());
132 Assert.assertEquals(16, metrics.getBytesTransferred());
133 }
134
135 @Test
136 public void testBasicDecodingSmallBuffer() throws Exception {
137 final ReadableByteChannel channel = new ReadableByteChannelMock(
138 new String[] {"stuff;", "more stuff"}, Consts.ASCII);
139
140 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, Consts.ASCII);
141 final HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl();
142 final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder(
143 channel, inbuf, metrics, 16);
144
145 final ByteBuffer dst = ByteBuffer.allocate(4);
146
147 int bytesRead = decoder.read(dst);
148 Assert.assertEquals(4, bytesRead);
149 Assert.assertEquals("stuf", CodecTestUtils.convert(dst));
150 Assert.assertFalse(decoder.isCompleted());
151 Assert.assertEquals(4, metrics.getBytesTransferred());
152
153 dst.clear();
154 bytesRead = decoder.read(dst);
155 Assert.assertEquals(2, bytesRead);
156 Assert.assertEquals("f;", CodecTestUtils.convert(dst));
157 Assert.assertFalse(decoder.isCompleted());
158 Assert.assertEquals(6, metrics.getBytesTransferred());
159
160 dst.clear();
161 bytesRead = decoder.read(dst);
162 Assert.assertEquals(4, bytesRead);
163 Assert.assertEquals("more", CodecTestUtils.convert(dst));
164 Assert.assertFalse(decoder.isCompleted());
165 Assert.assertEquals(10, metrics.getBytesTransferred());
166
167 dst.clear();
168 bytesRead = decoder.read(dst);
169 Assert.assertEquals(4, bytesRead);
170 Assert.assertEquals(" stu", CodecTestUtils.convert(dst));
171 Assert.assertFalse(decoder.isCompleted());
172 Assert.assertEquals(14, metrics.getBytesTransferred());
173
174 dst.clear();
175 bytesRead = decoder.read(dst);
176 Assert.assertEquals(2, bytesRead);
177 Assert.assertEquals("ff", CodecTestUtils.convert(dst));
178 Assert.assertTrue(decoder.isCompleted());
179 Assert.assertEquals(16, metrics.getBytesTransferred());
180
181 dst.clear();
182 bytesRead = decoder.read(dst);
183 Assert.assertEquals(-1, bytesRead);
184 Assert.assertTrue(decoder.isCompleted());
185 Assert.assertEquals(16, metrics.getBytesTransferred());
186 }
187
188 @Test
189 public void testDecodingFromSessionBuffer1() throws Exception {
190 final ReadableByteChannel channel = new ReadableByteChannelMock(
191 new String[] {"stuff;", "more stuff"}, Consts.ASCII);
192
193 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, Consts.ASCII);
194 final HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl();
195
196 inbuf.fill(channel);
197
198 Assert.assertEquals(6, inbuf.length());
199
200 final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder(
201 channel, inbuf, metrics, 16);
202
203 final ByteBuffer dst = ByteBuffer.allocate(1024);
204
205 int bytesRead = decoder.read(dst);
206 Assert.assertEquals(6, bytesRead);
207 Assert.assertEquals("stuff;", CodecTestUtils.convert(dst));
208 Assert.assertFalse(decoder.isCompleted());
209 Assert.assertEquals(0, metrics.getBytesTransferred());
210
211 dst.clear();
212 bytesRead = decoder.read(dst);
213 Assert.assertEquals(10, bytesRead);
214 Assert.assertEquals("more stuff", CodecTestUtils.convert(dst));
215 Assert.assertTrue(decoder.isCompleted());
216 Assert.assertEquals(10, metrics.getBytesTransferred());
217
218 dst.clear();
219 bytesRead = decoder.read(dst);
220 Assert.assertEquals(-1, bytesRead);
221 Assert.assertTrue(decoder.isCompleted());
222 Assert.assertEquals(10, metrics.getBytesTransferred());
223 }
224
225 @Test
226 public void testDecodingFromSessionBuffer2() throws Exception {
227 final ReadableByteChannel channel = new ReadableByteChannelMock(
228 new String[] {
229 "stuff;",
230 "more stuff; and a lot more stuff"}, Consts.ASCII);
231
232 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, Consts.ASCII);
233 final HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl();
234
235 inbuf.fill(channel);
236 inbuf.fill(channel);
237
238 Assert.assertEquals(38, inbuf.length());
239
240 final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder(
241 channel, inbuf, metrics, 16);
242
243 final ByteBuffer dst = ByteBuffer.allocate(1024);
244
245 int bytesRead = decoder.read(dst);
246 Assert.assertEquals(16, bytesRead);
247 Assert.assertEquals("stuff;more stuff", CodecTestUtils.convert(dst));
248 Assert.assertTrue(decoder.isCompleted());
249 Assert.assertEquals(0, metrics.getBytesTransferred());
250
251 dst.clear();
252 bytesRead = decoder.read(dst);
253 Assert.assertEquals(-1, bytesRead);
254 Assert.assertTrue(decoder.isCompleted());
255 Assert.assertEquals(0, metrics.getBytesTransferred());
256 }
257
258
259 @Test
260 public void testBasicDecodingFile() throws Exception {
261 final ReadableByteChannel channel = new ReadableByteChannelMock(
262 new String[] {"stuff; ", "more stuff; ", "a lot more stuff!!!"}, Consts.ASCII);
263
264 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, Consts.ASCII);
265 final HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl();
266 final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder(
267 channel, inbuf, metrics, 36);
268
269 createTempFile();
270 final RandomAccessFile testfile = new RandomAccessFile(this.tmpfile, "rw");
271 try {
272 final FileChannel fchannel = testfile.getChannel();
273 long pos = 0;
274 while (!decoder.isCompleted()) {
275 final long bytesRead = decoder.transfer(fchannel, pos, 10);
276 if (bytesRead > 0) {
277 pos += bytesRead;
278 }
279 }
280 } finally {
281 testfile.close();
282 }
283 Assert.assertEquals(this.tmpfile.length(), metrics.getBytesTransferred());
284 Assert.assertEquals("stuff; more stuff; a lot more stuff!",
285 CodecTestUtils.readFromFile(this.tmpfile));
286 }
287
288 @Test
289 public void testDecodingFileWithBufferedSessionData() throws Exception {
290 final ReadableByteChannel channel = new ReadableByteChannelMock(
291 new String[] {"stuff; ", "more stuff; ", "a lot more stuff!!!"}, Consts.ASCII);
292
293 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, Consts.ASCII);
294 final HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl();
295 final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder(
296 channel, inbuf, metrics, 36);
297
298 final int i = inbuf.fill(channel);
299 Assert.assertEquals(7, i);
300
301 createTempFile();
302 final RandomAccessFile testfile = new RandomAccessFile(this.tmpfile, "rw");
303 try {
304 final FileChannel fchannel = testfile.getChannel();
305 long pos = 0;
306 while (!decoder.isCompleted()) {
307 final long bytesRead = decoder.transfer(fchannel, pos, 10);
308 if (bytesRead > 0) {
309 pos += bytesRead;
310 }
311 }
312 } finally {
313 testfile.close();
314 }
315 Assert.assertEquals(this.tmpfile.length() - 7, metrics.getBytesTransferred());
316 Assert.assertEquals("stuff; more stuff; a lot more stuff!",
317 CodecTestUtils.readFromFile(this.tmpfile));
318 }
319
320 @Test
321 public void testDecodingFileWithOffsetAndBufferedSessionData() throws Exception {
322 final ReadableByteChannel channel = new ReadableByteChannelMock(
323 new String[] {"stuff; ", "more stuff; ", "a lot more stuff!"}, Consts.ASCII);
324
325 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, Consts.ASCII);
326 final HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl();
327 final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder(
328 channel, inbuf, metrics, 36);
329
330 final int i = inbuf.fill(channel);
331 Assert.assertEquals(7, i);
332
333 final byte[] beginning = EncodingUtils.getAsciiBytes("beginning; ");
334
335 createTempFile();
336 RandomAccessFile testfile = new RandomAccessFile(this.tmpfile, "rw");
337 try {
338 testfile.write(beginning);
339 } finally {
340 testfile.close();
341 }
342
343 testfile = new RandomAccessFile(this.tmpfile, "rw");
344 try {
345 final FileChannel fchannel = testfile.getChannel();
346
347 long pos = beginning.length;
348 while (!decoder.isCompleted()) {
349 if(testfile.length() < pos) {
350 testfile.setLength(pos);
351 }
352 final long bytesRead = decoder.transfer(fchannel, pos, 10);
353 if (bytesRead > 0) {
354 pos += bytesRead;
355 }
356 }
357 } finally {
358 testfile.close();
359 }
360
361
362 Assert.assertEquals(this.tmpfile.length() - 7 - beginning.length, metrics.getBytesTransferred());
363 Assert.assertEquals("beginning; stuff; more stuff; a lot more stuff!",
364 CodecTestUtils.readFromFile(this.tmpfile));
365 }
366
367 @Test
368 public void testDecodingFileWithLimit() throws Exception {
369 final ReadableByteChannel channel = new ReadableByteChannelMock(
370 new String[] {"stuff; more stuff; ", "a lot more stuff!!!"}, Consts.ASCII);
371
372 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, Consts.ASCII);
373 final HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl();
374 final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder(
375 channel, inbuf, metrics, 36);
376
377 final int i = inbuf.fill(channel);
378 Assert.assertEquals(19, i);
379
380 createTempFile();
381 final RandomAccessFile testfile = new RandomAccessFile(this.tmpfile, "rw");
382 try {
383 final FileChannel fchannel = testfile.getChannel();
384 long pos = 0;
385
386
387 long bytesRead = decoder.transfer(fchannel, pos, 1);
388 Assert.assertEquals(1, bytesRead);
389 Assert.assertFalse(decoder.isCompleted());
390 Assert.assertEquals(0, metrics.getBytesTransferred());
391 pos += bytesRead;
392
393 bytesRead = decoder.transfer(fchannel, pos, 2);
394 Assert.assertEquals(2, bytesRead);
395 Assert.assertFalse(decoder.isCompleted());
396 Assert.assertEquals(0, metrics.getBytesTransferred());
397 pos += bytesRead;
398
399 bytesRead = decoder.transfer(fchannel, pos, 17);
400 Assert.assertEquals(16, bytesRead);
401 Assert.assertFalse(decoder.isCompleted());
402 Assert.assertEquals(0, metrics.getBytesTransferred());
403 pos += bytesRead;
404
405
406 bytesRead = decoder.transfer(fchannel, pos, 1);
407 Assert.assertEquals(1, bytesRead);
408 Assert.assertFalse(decoder.isCompleted());
409 Assert.assertEquals(1, metrics.getBytesTransferred());
410 pos += bytesRead;
411
412 bytesRead = decoder.transfer(fchannel, pos, 2);
413 Assert.assertEquals(2, bytesRead);
414 Assert.assertFalse(decoder.isCompleted());
415 Assert.assertEquals(3, metrics.getBytesTransferred());
416 pos += bytesRead;
417
418 bytesRead = decoder.transfer(fchannel, pos, 15);
419 Assert.assertEquals(14, bytesRead);
420 Assert.assertTrue(decoder.isCompleted());
421 Assert.assertEquals(17, metrics.getBytesTransferred());
422 pos += bytesRead;
423
424 bytesRead = decoder.transfer(fchannel, pos, 1);
425 Assert.assertEquals(-1, bytesRead);
426 Assert.assertTrue(decoder.isCompleted());
427 Assert.assertEquals(17, metrics.getBytesTransferred());
428 } finally {
429 testfile.close();
430 }
431 Assert.assertEquals("stuff; more stuff; a lot more stuff!",
432 CodecTestUtils.readFromFile(this.tmpfile));
433 }
434
435 @Test
436 public void testWriteBeyondFileSize() throws Exception {
437 final ReadableByteChannel channel = new ReadableByteChannelMock(
438 new String[] {"a"}, Consts.ASCII);
439
440 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, Consts.ASCII);
441 final HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl();
442 final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder(
443 channel, inbuf, metrics, 1);
444
445 createTempFile();
446 final RandomAccessFile testfile = new RandomAccessFile(this.tmpfile, "rw");
447 try {
448 final FileChannel fchannel = testfile.getChannel();
449 Assert.assertEquals(0, testfile.length());
450 try {
451 decoder.transfer(fchannel, 5, 10);
452 Assert.fail("IOException should have been thrown");
453 } catch(final IOException expected) {
454 }
455 } finally {
456 testfile.close();
457 }
458 }
459
460 @Test
461 public void testCodingBeyondContentLimitFile() throws Exception {
462 final ReadableByteChannel channel = new ReadableByteChannelMock(
463 new String[] {
464 "stuff;",
465 "more stuff; and a lot more stuff"}, Consts.ASCII);
466
467 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, Consts.ASCII);
468 final HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl();
469 final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder(
470 channel, inbuf, metrics, 16);
471
472 createTempFile();
473 final RandomAccessFile testfile = new RandomAccessFile(this.tmpfile, "rw");
474 try {
475 final FileChannel fchannel = testfile.getChannel();
476
477 long bytesRead = decoder.transfer(fchannel, 0, 6);
478 Assert.assertEquals(6, bytesRead);
479 Assert.assertFalse(decoder.isCompleted());
480 Assert.assertEquals(6, metrics.getBytesTransferred());
481
482 bytesRead = decoder.transfer(fchannel,0 , 10);
483 Assert.assertEquals(10, bytesRead);
484 Assert.assertTrue(decoder.isCompleted());
485 Assert.assertEquals(16, metrics.getBytesTransferred());
486
487 bytesRead = decoder.transfer(fchannel, 0, 1);
488 Assert.assertEquals(-1, bytesRead);
489 Assert.assertTrue(decoder.isCompleted());
490 Assert.assertEquals(16, metrics.getBytesTransferred());
491 } finally {
492 testfile.close();
493 }
494 }
495
496 @Test
497 public void testInvalidConstructor() {
498 final ReadableByteChannel channel = new ReadableByteChannelMock(
499 new String[] {"stuff;", "more stuff"}, Consts.ASCII);
500
501 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, Consts.ASCII);
502 final HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl();
503 try {
504 new LengthDelimitedDecoder(null, null, null, 10);
505 Assert.fail("IllegalArgumentException should have been thrown");
506 } catch (final IllegalArgumentException ex) {
507
508 }
509 try {
510 new LengthDelimitedDecoder(channel, null, null, 10);
511 Assert.fail("IllegalArgumentException should have been thrown");
512 } catch (final IllegalArgumentException ex) {
513
514 }
515 try {
516 new LengthDelimitedDecoder(channel, inbuf, null, 10);
517 Assert.fail("IllegalArgumentException should have been thrown");
518 } catch (final IllegalArgumentException ex) {
519
520 }
521 try {
522 new LengthDelimitedDecoder(channel, inbuf, metrics, -10);
523 Assert.fail("IllegalArgumentException should have been thrown");
524 } catch (final IllegalArgumentException ex) {
525
526 }
527 }
528
529 @Test
530 public void testInvalidInput() throws Exception {
531 final String s = "stuff";
532 final ReadableByteChannel channel = new ReadableByteChannelMock(
533 new String[] {s}, Consts.ASCII);
534
535 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, Consts.ASCII);
536 final HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl();
537 final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder(
538 channel, inbuf, metrics, 3);
539
540 try {
541 decoder.read(null);
542 Assert.fail("IllegalArgumentException should have been thrown");
543 } catch (final IllegalArgumentException ex) {
544
545 }
546 }
547
548 @Test
549 public void testZeroLengthDecoding() throws Exception {
550 final ReadableByteChannel channel = new ReadableByteChannelMock(
551 new String[] {"stuff"}, Consts.ASCII);
552
553 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, Consts.ASCII);
554 final HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl();
555 final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder(
556 channel, inbuf, metrics, 0);
557
558 final ByteBuffer dst = ByteBuffer.allocate(1024);
559
560 final int bytesRead = decoder.read(dst);
561 Assert.assertEquals(-1, bytesRead);
562 Assert.assertTrue(decoder.isCompleted());
563 Assert.assertEquals(0, metrics.getBytesTransferred());
564 }
565
566 @Test(expected=ConnectionClosedException.class)
567 public void testTruncatedContent() throws Exception {
568 final ReadableByteChannel channel = new ReadableByteChannelMock(
569 new String[] {"1234567890"}, Consts.ASCII);
570
571 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, Consts.ASCII);
572 final HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl();
573 final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder(
574 channel, inbuf, metrics, 20);
575
576 final ByteBuffer dst = ByteBuffer.allocate(1024);
577
578 final int bytesRead = decoder.read(dst);
579 Assert.assertEquals(10, bytesRead);
580 decoder.read(dst);
581 }
582
583 @Test(expected=ConnectionClosedException.class)
584 public void testTruncatedContentWithFile() throws Exception {
585 final ReadableByteChannel channel = new ReadableByteChannelMock(
586 new String[] {"1234567890"}, Consts.ASCII);
587
588 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, Consts.ASCII);
589 final HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl();
590 final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder(
591 channel, inbuf, metrics, 20);
592
593 createTempFile();
594 final RandomAccessFile testfile = new RandomAccessFile(this.tmpfile, "rw");
595 try {
596 final FileChannel fchannel = testfile.getChannel();
597 final long bytesRead = decoder.transfer(fchannel, 0, Integer.MAX_VALUE);
598 Assert.assertEquals(10, bytesRead);
599 decoder.transfer(fchannel, 0, Integer.MAX_VALUE);
600 } finally {
601 testfile.close();
602 }
603 }
604
605 }