1 /* 2 * $HeadURL: https://svn.apache.org/repos/asf/jakarta/httpcomponents/httpcore/tags/4.0-alpha2/src/test/org/apache/http/io/TestChunkCoding.java $ 3 * $Revision: 389604 $ 4 * $Date: 2006-03-28 23:03:47 +0200 (Tue, 28 Mar 2006) $ 5 * ==================================================================== 6 * 7 * Copyright 2002-2004 The Apache Software Foundation 8 * 9 * Licensed under the Apache License, Version 2.0 (the "License"); 10 * you may not use this file except in compliance with the License. 11 * You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 * ==================================================================== 21 * 22 * This software consists of voluntary contributions made by many 23 * individuals on behalf of the Apache Software Foundation. For more 24 * information on the Apache Software Foundation, please see 25 * <http://www.apache.org/>. 26 * 27 */ 28 29 package org.apache.http.io; 30 31 import java.io.ByteArrayOutputStream; 32 import java.io.IOException; 33 import java.io.InputStream; 34 import java.io.OutputStream; 35 36 import org.apache.http.Header; 37 import org.apache.http.mockup.HttpDataReceiverMockup; 38 import org.apache.http.mockup.HttpDataTransmitterMockup; 39 import org.apache.http.util.EncodingUtils; 40 41 import junit.framework.Test; 42 import junit.framework.TestCase; 43 import junit.framework.TestSuite; 44 45 public class TestChunkCoding extends TestCase { 46 47 private static final String CONTENT_CHARSET = "ISO-8859-1"; 48 49 public TestChunkCoding(String testName) { 50 super(testName); 51 } 52 53 // ------------------------------------------------------- TestCase Methods 54 55 public static Test suite() { 56 return new TestSuite(TestChunkCoding.class); 57 } 58 59 // ------------------------------------------------------------------- Main 60 public static void main(String args[]) { 61 String[] testCaseName = { TestChunkCoding.class.getName() }; 62 junit.textui.TestRunner.main(testCaseName); 63 } 64 65 public void testConstructors() throws Exception { 66 try { 67 new ChunkedInputStream((HttpDataReceiver)null); 68 fail("IllegalArgumentException should have been thrown"); 69 } catch (IllegalArgumentException ex) { 70 // expected 71 } 72 new MalformedChunkCodingException(); 73 new MalformedChunkCodingException(""); 74 } 75 76 private final static String CHUNKED_INPUT 77 = "10;key=\"value\"\r\n1234567890123456\r\n5\r\n12345\r\n0\r\nFooter1: abcde\r\nFooter2: fghij\r\n"; 78 79 private final static String CHUNKED_RESULT 80 = "123456789012345612345"; 81 82 // Test for when buffer is larger than chunk size 83 public void testChunkedInputStreamLargeBuffer() throws IOException { 84 ChunkedInputStream in = new ChunkedInputStream( 85 new HttpDataReceiverMockup( 86 EncodingUtils.getBytes(CHUNKED_INPUT, CONTENT_CHARSET))); 87 byte[] buffer = new byte[300]; 88 ByteArrayOutputStream out = new ByteArrayOutputStream(); 89 int len; 90 while ((len = in.read(buffer)) > 0) { 91 out.write(buffer, 0, len); 92 } 93 assertEquals(-1, in.read(buffer)); 94 assertEquals(-1, in.read(buffer)); 95 96 in.close(); 97 98 String result = EncodingUtils.getString(out.toByteArray(), CONTENT_CHARSET); 99 assertEquals(result, CHUNKED_RESULT); 100 101 Header[] footers = in.getFooters(); 102 assertNotNull(footers); 103 assertEquals(2, footers.length); 104 assertEquals("Footer1", footers[0].getName()); 105 assertEquals("abcde", footers[0].getValue()); 106 assertEquals("Footer2", footers[1].getName()); 107 assertEquals("fghij", footers[1].getValue()); 108 } 109 110 //Test for when buffer is smaller than chunk size. 111 public void testChunkedInputStreamSmallBuffer() throws IOException { 112 ChunkedInputStream in = new ChunkedInputStream( 113 new HttpDataReceiverMockup( 114 EncodingUtils.getBytes(CHUNKED_INPUT, CONTENT_CHARSET))); 115 116 byte[] buffer = new byte[7]; 117 ByteArrayOutputStream out = new ByteArrayOutputStream(); 118 int len; 119 while ((len = in.read(buffer)) > 0) { 120 out.write(buffer, 0, len); 121 } 122 assertEquals(-1, in.read(buffer)); 123 assertEquals(-1, in.read(buffer)); 124 125 in.close(); 126 127 EncodingUtils.getString(out.toByteArray(), CONTENT_CHARSET); 128 Header[] footers = in.getFooters(); 129 assertNotNull(footers); 130 assertEquals(2, footers.length); 131 assertEquals("Footer1", footers[0].getName()); 132 assertEquals("abcde", footers[0].getValue()); 133 assertEquals("Footer2", footers[1].getName()); 134 assertEquals("fghij", footers[1].getValue()); 135 } 136 137 // One byte read 138 public void testChunkedInputStreamOneByteRead() throws IOException { 139 String s = "5\r\n01234\r\n5\r\n56789\r\n0\r\n"; 140 ChunkedInputStream in = new ChunkedInputStream( 141 new HttpDataReceiverMockup( 142 EncodingUtils.getBytes(s, CONTENT_CHARSET))); 143 int ch; 144 int i = '0'; 145 while ((ch = in.read()) != -1) { 146 assertEquals(i, ch); 147 i++; 148 } 149 assertEquals(-1, in.read()); 150 assertEquals(-1, in.read()); 151 152 in.close(); 153 } 154 155 public void testChunkedInputStreamClose() throws IOException { 156 String s = "5\r\n01234\r\n5\r\n56789\r\n0\r\n"; 157 ChunkedInputStream in = new ChunkedInputStream( 158 new HttpDataReceiverMockup( 159 EncodingUtils.getBytes(s, CONTENT_CHARSET))); 160 in.close(); 161 in.close(); 162 try { 163 in.read(); 164 fail("IOException should have been thrown"); 165 } catch (IOException ex) { 166 // expected 167 } 168 byte[] tmp = new byte[10]; 169 try { 170 in.read(tmp); 171 fail("IOException should have been thrown"); 172 } catch (IOException ex) { 173 // expected 174 } 175 try { 176 in.read(tmp, 0, tmp.length); 177 fail("IOException should have been thrown"); 178 } catch (IOException ex) { 179 // expected 180 } 181 } 182 183 public void testChunkedOutputStreamClose() throws IOException { 184 ChunkedOutputStream out = new ChunkedOutputStream( 185 new HttpDataTransmitterMockup()); 186 out.close(); 187 out.close(); 188 try { 189 out.write(new byte[] {1,2,3}); 190 fail("IOException should have been thrown"); 191 } catch (IOException ex) { 192 // expected 193 } 194 try { 195 out.write(1); 196 fail("IOException should have been thrown"); 197 } catch (IOException ex) { 198 // expected 199 } 200 } 201 202 // Missing \r\n at the end of the first chunk 203 public void testCorruptChunkedInputStreamMissingCRLF() throws IOException { 204 String s = "5\r\n012345\r\n56789\r\n0\r\n"; 205 InputStream in = new ChunkedInputStream( 206 new HttpDataReceiverMockup( 207 EncodingUtils.getBytes(s, CONTENT_CHARSET))); 208 byte[] buffer = new byte[300]; 209 ByteArrayOutputStream out = new ByteArrayOutputStream(); 210 int len; 211 try { 212 while ((len = in.read(buffer)) > 0) { 213 out.write(buffer, 0, len); 214 } 215 fail("MalformedChunkCodingException should have been thrown"); 216 } catch(MalformedChunkCodingException e) { 217 /* expected exception */ 218 } 219 } 220 221 // Missing LF 222 public void testCorruptChunkedInputStreamMissingLF() throws IOException { 223 String s = "5\r01234\r\n5\r\n56789\r\n0\r\n"; 224 InputStream in = new ChunkedInputStream( 225 new HttpDataReceiverMockup( 226 EncodingUtils.getBytes(s, CONTENT_CHARSET))); 227 try { 228 in.read(); 229 fail("MalformedChunkCodingException should have been thrown"); 230 } catch(MalformedChunkCodingException e) { 231 /* expected exception */ 232 } 233 } 234 235 // Missing closing chunk 236 public void testCorruptChunkedInputStreamNoClosingChunk() throws IOException { 237 InputStream in = new ChunkedInputStream( 238 new HttpDataReceiverMockup(new byte[] {})); 239 try { 240 in.read(); 241 fail("MalformedChunkCodingException should have been thrown"); 242 } catch(MalformedChunkCodingException e) { 243 /* expected exception */ 244 } 245 } 246 247 // Invalid chunk size 248 public void testCorruptChunkedInputStreamInvalidSize() throws IOException { 249 String s = "whatever\r\n01234\r\n5\r\n56789\r\n0\r\n"; 250 InputStream in = new ChunkedInputStream( 251 new HttpDataReceiverMockup( 252 EncodingUtils.getBytes(s, CONTENT_CHARSET))); 253 try { 254 in.read(); 255 fail("MalformedChunkCodingException should have been thrown"); 256 } catch(MalformedChunkCodingException e) { 257 /* expected exception */ 258 } 259 } 260 261 // Negative chunk size 262 public void testCorruptChunkedInputStreamNegativeSize() throws IOException { 263 String s = "-5\r\n01234\r\n5\r\n56789\r\n0\r\n"; 264 InputStream in = new ChunkedInputStream( 265 new HttpDataReceiverMockup( 266 EncodingUtils.getBytes(s, CONTENT_CHARSET))); 267 try { 268 in.read(); 269 fail("MalformedChunkCodingException should have been thrown"); 270 } catch(MalformedChunkCodingException e) { 271 /* expected exception */ 272 } 273 } 274 275 // Invalid footer 276 public void testCorruptChunkedInputStreamInvalidFooter() throws IOException { 277 String s = "1\r\n0\r\n0\r\nstuff\r\n"; 278 InputStream in = new ChunkedInputStream( 279 new HttpDataReceiverMockup( 280 EncodingUtils.getBytes(s, CONTENT_CHARSET))); 281 try { 282 in.read(); 283 in.read(); 284 fail("MalformedChunkCodingException should have been thrown"); 285 } catch(MalformedChunkCodingException e) { 286 /* expected exception */ 287 } 288 } 289 290 public void testEmptyChunkedInputStream() throws IOException { 291 String input = "0\r\n"; 292 InputStream in = new ChunkedInputStream( 293 new HttpDataReceiverMockup( 294 EncodingUtils.getBytes(input, CONTENT_CHARSET))); 295 byte[] buffer = new byte[300]; 296 ByteArrayOutputStream out = new ByteArrayOutputStream(); 297 int len; 298 while ((len = in.read(buffer)) > 0) { 299 out.write(buffer, 0, len); 300 } 301 assertEquals(0, out.size()); 302 } 303 304 public void testChunkedConsitance() throws IOException { 305 String input = "76126;27823abcd;:q38a-\nkjc\rk%1ad\tkh/asdui\r\njkh+?\\suweb"; 306 ByteArrayOutputStream buffer = new ByteArrayOutputStream(); 307 OutputStream out = new ChunkedOutputStream(new HttpDataTransmitterMockup(buffer)); 308 out.write(EncodingUtils.getBytes(input, CONTENT_CHARSET)); 309 out.flush(); 310 out.close(); 311 out.close(); 312 buffer.close(); 313 InputStream in = new ChunkedInputStream( 314 new HttpDataReceiverMockup( 315 buffer.toByteArray())); 316 317 byte[] d = new byte[10]; 318 ByteArrayOutputStream result = new ByteArrayOutputStream(); 319 int len = 0; 320 while ((len = in.read(d)) > 0) { 321 result.write(d, 0, len); 322 } 323 324 String output = EncodingUtils.getString(result.toByteArray(), CONTENT_CHARSET); 325 assertEquals(input, output); 326 } 327 328 public void testChunkedOutputStream() throws IOException { 329 HttpDataTransmitterMockup buffer = new HttpDataTransmitterMockup(); 330 ChunkedOutputStream out = new ChunkedOutputStream(buffer, 2); 331 out.write('1'); 332 out.write('2'); 333 out.write('3'); 334 out.write('4'); 335 out.finish(); 336 out.close(); 337 338 byte [] rawdata = buffer.getData(); 339 340 assertEquals(19, rawdata.length); 341 assertEquals('2', rawdata[0]); 342 assertEquals('\r', rawdata[1]); 343 assertEquals('\n', rawdata[2]); 344 assertEquals('1', rawdata[3]); 345 assertEquals('2', rawdata[4]); 346 assertEquals('\r', rawdata[5]); 347 assertEquals('\n', rawdata[6]); 348 assertEquals('2', rawdata[7]); 349 assertEquals('\r', rawdata[8]); 350 assertEquals('\n', rawdata[9]); 351 assertEquals('3', rawdata[10]); 352 assertEquals('4', rawdata[11]); 353 assertEquals('\r', rawdata[12]); 354 assertEquals('\n', rawdata[13]); 355 assertEquals('0', rawdata[14]); 356 assertEquals('\r', rawdata[15]); 357 assertEquals('\n', rawdata[16]); 358 assertEquals('\r', rawdata[17]); 359 assertEquals('\n', rawdata[18]); 360 } 361 362 public void testChunkedOutputStreamLargeChunk() throws IOException { 363 HttpDataTransmitterMockup buffer = new HttpDataTransmitterMockup(); 364 ChunkedOutputStream out = new ChunkedOutputStream(buffer, 2); 365 out.write(new byte[] {'1', '2', '3', '4'}); 366 out.finish(); 367 out.close(); 368 369 byte [] rawdata = buffer.getData(); 370 371 assertEquals(14, rawdata.length); 372 assertEquals('4', rawdata[0]); 373 assertEquals('\r', rawdata[1]); 374 assertEquals('\n', rawdata[2]); 375 assertEquals('1', rawdata[3]); 376 assertEquals('2', rawdata[4]); 377 assertEquals('3', rawdata[5]); 378 assertEquals('4', rawdata[6]); 379 assertEquals('\r', rawdata[7]); 380 assertEquals('\n', rawdata[8]); 381 assertEquals('0', rawdata[9]); 382 assertEquals('\r', rawdata[10]); 383 assertEquals('\n', rawdata[11]); 384 assertEquals('\r', rawdata[12]); 385 assertEquals('\n', rawdata[13]); 386 } 387 388 public void testChunkedOutputStreamSmallChunk() throws IOException { 389 ByteArrayOutputStream buffer = new ByteArrayOutputStream(); 390 ChunkedOutputStream out = new ChunkedOutputStream( 391 new HttpDataTransmitterMockup(buffer), 2); 392 out.write('1'); 393 out.finish(); 394 out.close(); 395 396 byte [] rawdata = buffer.toByteArray(); 397 398 assertEquals(11, rawdata.length); 399 assertEquals('1', rawdata[0]); 400 assertEquals('\r', rawdata[1]); 401 assertEquals('\n', rawdata[2]); 402 assertEquals('1', rawdata[3]); 403 assertEquals('\r', rawdata[4]); 404 assertEquals('\n', rawdata[5]); 405 assertEquals('0', rawdata[6]); 406 assertEquals('\r', rawdata[7]); 407 assertEquals('\n', rawdata[8]); 408 assertEquals('\r', rawdata[9]); 409 assertEquals('\n', rawdata[10]); 410 } 411 412 } 413