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.io;
29
30 import java.io.ByteArrayOutputStream;
31 import java.io.IOException;
32 import java.io.InputStream;
33 import java.io.InterruptedIOException;
34 import java.io.OutputStream;
35
36 import org.apache.http.ConnectionClosedException;
37 import org.apache.http.Consts;
38 import org.apache.http.Header;
39 import org.apache.http.MalformedChunkCodingException;
40 import org.apache.http.MessageConstraintException;
41 import org.apache.http.TruncatedChunkException;
42 import org.apache.http.config.MessageConstraints;
43 import org.apache.http.impl.SessionInputBufferMock;
44 import org.apache.http.impl.SessionOutputBufferMock;
45 import org.apache.http.io.SessionInputBuffer;
46 import org.junit.Assert;
47 import org.junit.Test;
48
49 public class TestChunkCoding {
50
51 @Test
52 public void testConstructors() throws Exception {
53 try {
54 new ChunkedInputStream((SessionInputBuffer)null);
55 Assert.fail("IllegalArgumentException should have been thrown");
56 } catch (final IllegalArgumentException ex) {
57
58 }
59 new MalformedChunkCodingException();
60 new MalformedChunkCodingException("");
61 }
62
63 private final static String CHUNKED_INPUT
64 = "10;key=\"value\"\r\n1234567890123456\r\n5\r\n12345\r\n0\r\nFooter1: abcde\r\nFooter2: fghij\r\n";
65
66 private final static String CHUNKED_RESULT
67 = "123456789012345612345";
68
69
70 @Test
71 public void testChunkedInputStreamLargeBuffer() throws IOException {
72 final ChunkedInputStream in = new ChunkedInputStream(
73 new SessionInputBufferMock(CHUNKED_INPUT, Consts.ISO_8859_1));
74 final byte[] buffer = new byte[300];
75 final ByteArrayOutputStream out = new ByteArrayOutputStream();
76 int len;
77 while ((len = in.read(buffer)) > 0) {
78 out.write(buffer, 0, len);
79 }
80 Assert.assertEquals(-1, in.read(buffer));
81 Assert.assertEquals(-1, in.read(buffer));
82
83 in.close();
84
85 final String result = new String(out.toByteArray(), Consts.ISO_8859_1);
86 Assert.assertEquals(result, CHUNKED_RESULT);
87
88 final Header[] footers = in.getFooters();
89 Assert.assertNotNull(footers);
90 Assert.assertEquals(2, footers.length);
91 Assert.assertEquals("Footer1", footers[0].getName());
92 Assert.assertEquals("abcde", footers[0].getValue());
93 Assert.assertEquals("Footer2", footers[1].getName());
94 Assert.assertEquals("fghij", footers[1].getValue());
95 }
96
97
98 @Test
99 public void testChunkedInputStreamSmallBuffer() throws IOException {
100 final ChunkedInputStream in = new ChunkedInputStream(
101 new SessionInputBufferMock(CHUNKED_INPUT, Consts.ISO_8859_1));
102
103 final byte[] buffer = new byte[7];
104 final ByteArrayOutputStream out = new ByteArrayOutputStream();
105 int len;
106 while ((len = in.read(buffer)) > 0) {
107 out.write(buffer, 0, len);
108 }
109 Assert.assertEquals(-1, in.read(buffer));
110 Assert.assertEquals(-1, in.read(buffer));
111
112 in.close();
113
114 final Header[] footers = in.getFooters();
115 Assert.assertNotNull(footers);
116 Assert.assertEquals(2, footers.length);
117 Assert.assertEquals("Footer1", footers[0].getName());
118 Assert.assertEquals("abcde", footers[0].getValue());
119 Assert.assertEquals("Footer2", footers[1].getName());
120 Assert.assertEquals("fghij", footers[1].getValue());
121 }
122
123
124 @Test
125 public void testChunkedInputStreamOneByteRead() throws IOException {
126 final String s = "5\r\n01234\r\n5\r\n56789\r\n0\r\n";
127 final ChunkedInputStream in = new ChunkedInputStream(
128 new SessionInputBufferMock(s, Consts.ISO_8859_1));
129 int ch;
130 int i = '0';
131 while ((ch = in.read()) != -1) {
132 Assert.assertEquals(i, ch);
133 i++;
134 }
135 Assert.assertEquals(-1, in.read());
136 Assert.assertEquals(-1, in.read());
137
138 in.close();
139 }
140
141 @Test
142 public void testAvailable() throws IOException {
143 final String s = "5\r\n12345\r\n0\r\n";
144 final ChunkedInputStream in = new ChunkedInputStream(
145 new SessionInputBufferMock(s, Consts.ISO_8859_1));
146 Assert.assertEquals(0, in.available());
147 in.read();
148 Assert.assertEquals(4, in.available());
149 in.close();
150 }
151
152 @Test
153 public void testChunkedInputStreamClose() throws IOException {
154 final String s = "5\r\n01234\r\n5\r\n56789\r\n0\r\n";
155 final ChunkedInputStream in = new ChunkedInputStream(
156 new SessionInputBufferMock(s, Consts.ISO_8859_1));
157 in.close();
158 in.close();
159 try {
160 in.read();
161 Assert.fail("IOException should have been thrown");
162 } catch (final IOException ex) {
163
164 }
165 final byte[] tmp = new byte[10];
166 try {
167 in.read(tmp);
168 Assert.fail("IOException should have been thrown");
169 } catch (final IOException ex) {
170
171 }
172 try {
173 in.read(tmp, 0, tmp.length);
174 Assert.fail("IOException should have been thrown");
175 } catch (final IOException ex) {
176
177 }
178 }
179
180 @Test
181 public void testChunkedOutputStreamClose() throws IOException {
182 final ChunkedOutputStream out = new ChunkedOutputStream(
183 2048, new SessionOutputBufferMock());
184 out.close();
185 out.close();
186 try {
187 out.write(new byte[] {1,2,3});
188 Assert.fail("IOException should have been thrown");
189 } catch (final IOException ex) {
190
191 }
192 try {
193 out.write(1);
194 Assert.fail("IOException should have been thrown");
195 } catch (final IOException ex) {
196
197 }
198 }
199
200
201 @Test(expected=ConnectionClosedException.class)
202 public void testChunkedInputStreamNoClosingChunk() throws IOException {
203 final String s = "5\r\n01234\r\n";
204 final ChunkedInputStream in = new ChunkedInputStream(
205 new SessionInputBufferMock(s, Consts.ISO_8859_1));
206 final byte[] tmp = new byte[5];
207 Assert.assertEquals(5, in.read(tmp));
208 in.read();
209 in.close();
210 }
211
212
213 @Test(expected=MalformedChunkCodingException.class)
214 public void testCorruptChunkedInputStreamTruncatedCRLF() throws IOException {
215 final String s = "5\r\n01234";
216 final ChunkedInputStream in = new ChunkedInputStream(
217 new SessionInputBufferMock(s, Consts.ISO_8859_1));
218 final byte[] tmp = new byte[5];
219 Assert.assertEquals(5, in.read(tmp));
220 in.read();
221 in.close();
222 }
223
224
225 @Test(expected=MalformedChunkCodingException.class)
226 public void testCorruptChunkedInputStreamMissingCRLF() throws IOException {
227 final String s = "5\r\n012345\r\n56789\r\n0\r\n";
228 final InputStream in = new ChunkedInputStream(
229 new SessionInputBufferMock(s, Consts.ISO_8859_1));
230 final byte[] buffer = new byte[300];
231 final ByteArrayOutputStream out = new ByteArrayOutputStream();
232 int len;
233 while ((len = in.read(buffer)) > 0) {
234 out.write(buffer, 0, len);
235 }
236 in.close();
237 }
238
239
240 @Test(expected=MalformedChunkCodingException.class)
241 public void testCorruptChunkedInputStreamMissingLF() throws IOException {
242 final String s = "5\r01234\r\n5\r\n56789\r\n0\r\n";
243 final InputStream in = new ChunkedInputStream(
244 new SessionInputBufferMock(s, Consts.ISO_8859_1));
245 in.read();
246 in.close();
247 }
248
249
250 @Test(expected = MalformedChunkCodingException.class)
251 public void testCorruptChunkedInputStreamInvalidSize() throws IOException {
252 final String s = "whatever\r\n01234\r\n5\r\n56789\r\n0\r\n";
253 final InputStream in = new ChunkedInputStream(
254 new SessionInputBufferMock(s, Consts.ISO_8859_1));
255 in.read();
256 in.close();
257 }
258
259
260 @Test(expected = MalformedChunkCodingException.class)
261 public void testCorruptChunkedInputStreamNegativeSize() throws IOException {
262 final String s = "-5\r\n01234\r\n5\r\n56789\r\n0\r\n";
263 final InputStream in = new ChunkedInputStream(
264 new SessionInputBufferMock(s, Consts.ISO_8859_1));
265 in.read();
266 in.close();
267 }
268
269
270 @Test(expected = TruncatedChunkException.class)
271 public void testCorruptChunkedInputStreamTruncatedChunk() throws IOException {
272 final String s = "3\r\n12";
273 final InputStream in = new ChunkedInputStream(
274 new SessionInputBufferMock(s, Consts.ISO_8859_1));
275 final byte[] buffer = new byte[300];
276 Assert.assertEquals(2, in.read(buffer));
277 in.read(buffer);
278 in.close();
279 }
280
281
282 @Test(expected = MalformedChunkCodingException.class)
283 public void testCorruptChunkedInputStreamInvalidFooter() throws IOException {
284 final String s = "1\r\n0\r\n0\r\nstuff\r\n";
285 final InputStream in = new ChunkedInputStream(
286 new SessionInputBufferMock(s, Consts.ISO_8859_1));
287 in.read();
288 in.read();
289 in.close();
290 }
291
292 @Test
293 public void testCorruptChunkedInputStreamClose() throws IOException {
294 final String s = "whatever\r\n01234\r\n5\r\n56789\r\n0\r\n";
295 final InputStream in = new ChunkedInputStream(
296 new SessionInputBufferMock(s, Consts.ISO_8859_1));
297 try {
298 in.read();
299 Assert.fail("MalformedChunkCodingException expected");
300 } catch (final MalformedChunkCodingException ex) {
301 }
302 in.close();
303 }
304
305 @Test
306 public void testEmptyChunkedInputStream() throws IOException {
307 final String input = "0\r\n";
308 final InputStream in = new ChunkedInputStream(
309 new SessionInputBufferMock(input, Consts.ISO_8859_1));
310 final byte[] buffer = new byte[300];
311 final ByteArrayOutputStream out = new ByteArrayOutputStream();
312 int len;
313 while ((len = in.read(buffer)) > 0) {
314 out.write(buffer, 0, len);
315 }
316 Assert.assertEquals(0, out.size());
317 in.close();
318 }
319
320 @Test
321 public void testTooLongChunkHeader() throws IOException {
322 final String input = "5; and some very looooong commend\r\n12345\r\n0\r\n";
323 final InputStream in1 = new ChunkedInputStream(
324 new SessionInputBufferMock(input, MessageConstraints.DEFAULT, Consts.ISO_8859_1));
325 final byte[] buffer = new byte[300];
326 Assert.assertEquals(5, in1.read(buffer));
327 in1.close();
328
329 final InputStream in2 = new ChunkedInputStream(
330 new SessionInputBufferMock(input, MessageConstraints.lineLen(10), Consts.ISO_8859_1));
331 try {
332 in2.read(buffer);
333 Assert.fail("MessageConstraintException expected");
334 } catch (final MessageConstraintException ex) {
335 } finally {
336 try {
337 in2.close();
338 } catch (final MessageConstraintException ex) {
339 }
340 }
341 }
342
343 @Test
344 public void testChunkedConsistence() throws IOException {
345 final String input = "76126;27823abcd;:q38a-\nkjc\rk%1ad\tkh/asdui\r\njkh+?\\suweb";
346 final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
347 final OutputStream out = new ChunkedOutputStream(2048, new SessionOutputBufferMock(buffer));
348 out.write(input.getBytes(Consts.ISO_8859_1));
349 out.flush();
350 out.close();
351 out.close();
352 buffer.close();
353 final InputStream in = new ChunkedInputStream(new SessionInputBufferMock(buffer.toByteArray()));
354
355 final byte[] d = new byte[10];
356 final ByteArrayOutputStream result = new ByteArrayOutputStream();
357 int len = 0;
358 while ((len = in.read(d)) > 0) {
359 result.write(d, 0, len);
360 }
361
362 final String output = new String(result.toByteArray(), Consts.ISO_8859_1);
363 Assert.assertEquals(input, output);
364 in.close();
365 }
366
367 @Test
368 public void testChunkedOutputStream() throws IOException {
369 final SessionOutputBufferMockck.html#SessionOutputBufferMock">SessionOutputBufferMock buffer = new SessionOutputBufferMock();
370 final ChunkedOutputStream out = new ChunkedOutputStream(2, buffer);
371 out.write('1');
372 out.write('2');
373 out.write('3');
374 out.write('4');
375 out.finish();
376 out.close();
377
378 final byte [] rawdata = buffer.getData();
379
380 Assert.assertEquals(19, rawdata.length);
381 Assert.assertEquals('2', rawdata[0]);
382 Assert.assertEquals('\r', rawdata[1]);
383 Assert.assertEquals('\n', rawdata[2]);
384 Assert.assertEquals('1', rawdata[3]);
385 Assert.assertEquals('2', rawdata[4]);
386 Assert.assertEquals('\r', rawdata[5]);
387 Assert.assertEquals('\n', rawdata[6]);
388 Assert.assertEquals('2', rawdata[7]);
389 Assert.assertEquals('\r', rawdata[8]);
390 Assert.assertEquals('\n', rawdata[9]);
391 Assert.assertEquals('3', rawdata[10]);
392 Assert.assertEquals('4', rawdata[11]);
393 Assert.assertEquals('\r', rawdata[12]);
394 Assert.assertEquals('\n', rawdata[13]);
395 Assert.assertEquals('0', rawdata[14]);
396 Assert.assertEquals('\r', rawdata[15]);
397 Assert.assertEquals('\n', rawdata[16]);
398 Assert.assertEquals('\r', rawdata[17]);
399 Assert.assertEquals('\n', rawdata[18]);
400 }
401
402 @Test
403 public void testChunkedOutputStreamLargeChunk() throws IOException {
404 final SessionOutputBufferMockck.html#SessionOutputBufferMock">SessionOutputBufferMock buffer = new SessionOutputBufferMock();
405 final ChunkedOutputStream out = new ChunkedOutputStream(2, buffer);
406 out.write(new byte[] {'1', '2', '3', '4'});
407 out.finish();
408 out.close();
409
410 final byte [] rawdata = buffer.getData();
411
412 Assert.assertEquals(14, rawdata.length);
413 Assert.assertEquals('4', rawdata[0]);
414 Assert.assertEquals('\r', rawdata[1]);
415 Assert.assertEquals('\n', rawdata[2]);
416 Assert.assertEquals('1', rawdata[3]);
417 Assert.assertEquals('2', rawdata[4]);
418 Assert.assertEquals('3', rawdata[5]);
419 Assert.assertEquals('4', rawdata[6]);
420 Assert.assertEquals('\r', rawdata[7]);
421 Assert.assertEquals('\n', rawdata[8]);
422 Assert.assertEquals('0', rawdata[9]);
423 Assert.assertEquals('\r', rawdata[10]);
424 Assert.assertEquals('\n', rawdata[11]);
425 Assert.assertEquals('\r', rawdata[12]);
426 Assert.assertEquals('\n', rawdata[13]);
427 }
428
429 @Test
430 public void testChunkedOutputStreamSmallChunk() throws IOException {
431 final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
432 final ChunkedOutputStream out = new ChunkedOutputStream(2, new SessionOutputBufferMock(buffer));
433 out.write('1');
434 out.finish();
435 out.close();
436
437 final byte [] rawdata = buffer.toByteArray();
438
439 Assert.assertEquals(11, rawdata.length);
440 Assert.assertEquals('1', rawdata[0]);
441 Assert.assertEquals('\r', rawdata[1]);
442 Assert.assertEquals('\n', rawdata[2]);
443 Assert.assertEquals('1', rawdata[3]);
444 Assert.assertEquals('\r', rawdata[4]);
445 Assert.assertEquals('\n', rawdata[5]);
446 Assert.assertEquals('0', rawdata[6]);
447 Assert.assertEquals('\r', rawdata[7]);
448 Assert.assertEquals('\n', rawdata[8]);
449 Assert.assertEquals('\r', rawdata[9]);
450 Assert.assertEquals('\n', rawdata[10]);
451 }
452
453 @Test
454 public void testResumeOnSocketTimeoutInData() throws IOException {
455 final String s = "5\r\n01234\r\n5\r\n5\0006789\r\na\r\n0123\000456789\r\n0\r\n";
456 final SessionInputBuffer sessbuf = new SessionInputBufferMock(
457 new TimeoutByteArrayInputStream(s.getBytes(Consts.ISO_8859_1)), 16);
458 final InputStream in = new ChunkedInputStream(sessbuf);
459
460 final byte[] tmp = new byte[3];
461
462 int bytesRead = 0;
463 int timeouts = 0;
464
465 int i = 0;
466 while (i != -1) {
467 try {
468 i = in.read(tmp);
469 if (i > 0) {
470 bytesRead += i;
471 }
472 } catch (final InterruptedIOException ex) {
473 timeouts++;
474 }
475 }
476 Assert.assertEquals(20, bytesRead);
477 Assert.assertEquals(2, timeouts);
478 in.close();
479 }
480
481 @Test
482 public void testResumeOnSocketTimeoutInChunk() throws IOException {
483 final String s = "5\000\r\000\n\00001234\r\n\0005\r\n56789\r\na\r\n0123456789\r\n\0000\r\n";
484 final SessionInputBuffer sessbuf = new SessionInputBufferMock(
485 new TimeoutByteArrayInputStream(s.getBytes(Consts.ISO_8859_1)), 16);
486 final InputStream in = new ChunkedInputStream(sessbuf);
487
488 final byte[] tmp = new byte[3];
489
490 int bytesRead = 0;
491 int timeouts = 0;
492
493 int i = 0;
494 while (i != -1) {
495 try {
496 i = in.read(tmp);
497 if (i > 0) {
498 bytesRead += i;
499 }
500 } catch (final InterruptedIOException ex) {
501 timeouts++;
502 }
503 }
504 Assert.assertEquals(20, bytesRead);
505 Assert.assertEquals(5, timeouts);
506 in.close();
507 }
508
509
510 @Test
511 public void testHugeChunk() throws IOException {
512 final ChunkedInputStream in = new ChunkedInputStream(
513 new SessionInputBufferMock("1234567890abcdef\r\n01234567", Consts.ISO_8859_1));
514 final ByteArrayOutputStream out = new ByteArrayOutputStream();
515 for (int i = 0; i < 8; ++i) {
516 out.write(in.read());
517 }
518
519 final String result = new String(out.toByteArray(), Consts.ISO_8859_1);
520 Assert.assertEquals("01234567", result);
521 }
522
523 }
524