1   /*
2    * $HeadURL: https://svn.apache.org/repos/asf/httpcomponents/oac.hc3x/trunk/src/test/org/apache/commons/httpclient/TestStreams.java $
3    * $Revision: 1425331 $
4    * $Date: 2012-12-22 18:29:41 +0000 (Sat, 22 Dec 2012) $
5    * ====================================================================
6    *
7    *  Licensed to the Apache Software Foundation (ASF) under one or more
8    *  contributor license agreements.  See the NOTICE file distributed with
9    *  this work for additional information regarding copyright ownership.
10   *  The ASF licenses this file to You under the Apache License, Version 2.0
11   *  (the "License"); you may not use this file except in compliance with
12   *  the License.  You may obtain a copy of the License at
13   *
14   *      http://www.apache.org/licenses/LICENSE-2.0
15   *
16   *  Unless required by applicable law or agreed to in writing, software
17   *  distributed under the License is distributed on an "AS IS" BASIS,
18   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19   *  See the License for the specific language governing permissions and
20   *  limitations under the License.
21   * ====================================================================
22   *
23   * This software consists of voluntary contributions made by many
24   * individuals on behalf of the Apache Software Foundation.  For more
25   * information on the Apache Software Foundation, please see
26   * <http://www.apache.org/>.
27   *
28   * [Additional notices, if required by prior licensing conditions]
29   *
30   */
31  
32  package org.apache.commons.httpclient;
33  
34  import java.io.ByteArrayInputStream;
35  import java.io.ByteArrayOutputStream;
36  import java.io.IOException;
37  import java.io.InputStream;
38  import java.io.OutputStream;
39  
40  import junit.framework.Test;
41  import junit.framework.TestCase;
42  import junit.framework.TestSuite;
43  
44  import org.apache.commons.httpclient.methods.GetMethod;
45  import org.apache.commons.httpclient.util.EncodingUtil;
46  
47  
48  public class TestStreams extends TestCase {
49  
50      private static final String CONTENT_CHARSET = "ISO-8859-1";
51      
52      public TestStreams(String testName) {
53          super(testName);
54      }
55  
56      public void testChunkedInputStream() throws IOException {
57          String correctInput = "10;key=\"value\r\nnewline\"\r\n1234567890123456\r\n5\r\n12345\r\n0\r\nFooter1: abcde\r\nFooter2: fghij\r\n";
58          String correctResult = "123456789012345612345";
59          HttpMethod method = new FakeHttpMethod();
60  
61          //Test for when buffer is larger than chunk size
62          InputStream in = new ChunkedInputStream(new ByteArrayInputStream(
63              EncodingUtil.getBytes(correctInput, CONTENT_CHARSET)), method);
64          byte[] buffer = new byte[300];
65          ByteArrayOutputStream out = new ByteArrayOutputStream();
66          int len;
67          while ((len = in.read(buffer)) > 0) {
68              out.write(buffer, 0, len);
69          }
70          String result = EncodingUtil.getString(out.toByteArray(), CONTENT_CHARSET);
71          assertEquals(result, correctResult);
72          Header footer = method.getResponseFooter("footer1");
73          assertEquals(footer.getValue(), "abcde");
74          footer = method.getResponseFooter("footer2");
75          assertEquals(footer.getValue(), "fghij");
76  
77          method = new FakeHttpMethod();
78  
79          //Test for when buffer is smaller than chunk size.
80          in = new ChunkedInputStream(new ByteArrayInputStream(
81              EncodingUtil.getBytes(correctInput, CONTENT_CHARSET)), method);
82          buffer = new byte[7];
83          out = new ByteArrayOutputStream();
84          while ((len = in.read(buffer)) > 0) {
85              out.write(buffer, 0, len);
86          }
87          result = EncodingUtil.getString(out.toByteArray(), CONTENT_CHARSET);
88          assertEquals(result, correctResult);
89          footer = method.getResponseFooter("footer1");
90          assertEquals(footer.getValue(), "abcde");
91          footer = method.getResponseFooter("footer2");
92          assertEquals(footer.getValue(), "fghij");
93      }
94  
95      public void testCorruptChunkedInputStream1() throws IOException {
96          //missing \r\n at the end of the first chunk
97          String corrupInput = "10;key=\"value\"\r\n123456789012345\r\n5\r\n12345\r\n0\r\nFooter1: abcde\r\nFooter2: fghij\r\n";
98          HttpMethod method = new FakeHttpMethod();
99  
100         InputStream in = new ChunkedInputStream(new ByteArrayInputStream(
101             EncodingUtil.getBytes(corrupInput, CONTENT_CHARSET)), method);
102         byte[] buffer = new byte[300];
103         ByteArrayOutputStream out = new ByteArrayOutputStream();
104         int len;
105         try {
106             while ((len = in.read(buffer)) > 0) {
107                 out.write(buffer, 0, len);
108             }
109             fail("Should have thrown exception");
110         } catch(IOException e) {
111             /* expected exception */
112         }
113     }
114 
115     public void testEmptyChunkedInputStream() throws IOException {
116         String input = "0\r\n";
117         HttpMethod method = new FakeHttpMethod();
118 
119         InputStream in = new ChunkedInputStream(new ByteArrayInputStream(
120             EncodingUtil.getBytes(input, CONTENT_CHARSET)), method);
121         byte[] buffer = new byte[300];
122         ByteArrayOutputStream out = new ByteArrayOutputStream();
123         int len;
124         while ((len = in.read(buffer)) > 0) {
125             out.write(buffer, 0, len);
126         }
127         assertEquals(0, out.size());
128     }
129 
130     public void testContentLengthInputStream() throws IOException {
131         String correct = "1234567890123456";
132         InputStream in = new ContentLengthInputStream(new ByteArrayInputStream(
133             EncodingUtil.getBytes(correct, CONTENT_CHARSET)), 10L);
134         byte[] buffer = new byte[50];
135         int len = in.read(buffer);
136         ByteArrayOutputStream out = new ByteArrayOutputStream();
137         out.write(buffer, 0, len);
138         String result = EncodingUtil.getString(out.toByteArray(), CONTENT_CHARSET);
139         assertEquals(result, "1234567890");
140     }
141 
142     public void testContentLengthInputStreamSkip() throws IOException {
143         InputStream in = new ContentLengthInputStream(new ByteArrayInputStream(new byte[20]), 10L);
144         assertEquals(10, in.skip(10));
145         assertTrue(in.read() == -1);
146 
147         in = new ContentLengthInputStream(new ByteArrayInputStream(new byte[20]), 10L);
148         in.read();
149         assertEquals(9, in.skip(10));
150         assertTrue(in.read() == -1);
151 
152         in = new ContentLengthInputStream(new ByteArrayInputStream(new byte[20]), 2L);
153         in.read();
154         in.read();
155         assertTrue(in.skip(10) <= 0);
156         assertTrue(in.read() == -1);
157     }
158 
159     public void testChunkedConsitance() throws IOException {
160         String input = "76126;27823abcd;:q38a-\nkjc\rk%1ad\tkh/asdui\r\njkh+?//suweb";
161         ByteArrayOutputStream buffer = new ByteArrayOutputStream();
162         OutputStream out = new ChunkedOutputStream(buffer);
163         out.write(EncodingUtil.getBytes(input, CONTENT_CHARSET));
164         out.close();
165         buffer.close();
166         InputStream in = new ChunkedInputStream(new ByteArrayInputStream(buffer.toByteArray()), new GetMethod());
167 
168         byte[] d = new byte[10];
169         ByteArrayOutputStream result = new ByteArrayOutputStream();
170         int len = 0;
171         while ((len = in.read(d)) > 0) {
172             result.write(d, 0, len);
173         }
174 
175         String output = EncodingUtil.getString(result.toByteArray(), CONTENT_CHARSET);
176         assertEquals(input, output);
177     }
178 
179     public void testChunkedOutputStream() throws IOException {
180         ByteArrayOutputStream buffer = new ByteArrayOutputStream();
181         ChunkedOutputStream out = new ChunkedOutputStream(buffer, 2);
182         out.write('1');  
183         out.write('2');  
184         out.write('3');  
185         out.write('4');  
186         out.finish();
187         out.close();
188         
189         byte [] rawdata =  buffer.toByteArray();
190         
191         assertEquals(19, rawdata.length);
192         assertEquals('2', rawdata[0]);
193         assertEquals('\r', rawdata[1]);
194         assertEquals('\n', rawdata[2]);
195         assertEquals('1', rawdata[3]);
196         assertEquals('2', rawdata[4]);
197         assertEquals('\r', rawdata[5]);
198         assertEquals('\n', rawdata[6]);
199         assertEquals('2', rawdata[7]);
200         assertEquals('\r', rawdata[8]);
201         assertEquals('\n', rawdata[9]);
202         assertEquals('3', rawdata[10]);
203         assertEquals('4', rawdata[11]);
204         assertEquals('\r', rawdata[12]);
205         assertEquals('\n', rawdata[13]);
206         assertEquals('0', rawdata[14]);
207         assertEquals('\r', rawdata[15]);
208         assertEquals('\n', rawdata[16]);
209         assertEquals('\r', rawdata[17]);
210         assertEquals('\n', rawdata[18]);
211     }
212 
213     public void testChunkedOutputStreamLargeChunk() throws IOException {
214         ByteArrayOutputStream buffer = new ByteArrayOutputStream();
215         ChunkedOutputStream out = new ChunkedOutputStream(buffer, 2);
216         out.write(new byte[] {'1', '2', '3', '4'});
217         out.finish();
218         out.close();
219         
220         byte [] rawdata =  buffer.toByteArray();
221         
222         assertEquals(14, rawdata.length);
223         assertEquals('4', rawdata[0]);
224         assertEquals('\r', rawdata[1]);
225         assertEquals('\n', rawdata[2]);
226         assertEquals('1', rawdata[3]);
227         assertEquals('2', rawdata[4]);
228         assertEquals('3', rawdata[5]);
229         assertEquals('4', rawdata[6]);
230         assertEquals('\r', rawdata[7]);
231         assertEquals('\n', rawdata[8]);
232         assertEquals('0', rawdata[9]);
233         assertEquals('\r', rawdata[10]);
234         assertEquals('\n', rawdata[11]);
235         assertEquals('\r', rawdata[12]);
236         assertEquals('\n', rawdata[13]);
237     }
238 
239     public void testChunkedOutputStreamSmallChunk() throws IOException {
240         ByteArrayOutputStream buffer = new ByteArrayOutputStream();
241         ChunkedOutputStream out = new ChunkedOutputStream(buffer, 2);
242         out.write('1');  
243         out.finish();
244         out.close();
245         
246         byte [] rawdata =  buffer.toByteArray();
247         
248         assertEquals(11, rawdata.length);
249         assertEquals('1', rawdata[0]);
250         assertEquals('\r', rawdata[1]);
251         assertEquals('\n', rawdata[2]);
252         assertEquals('1', rawdata[3]);
253         assertEquals('\r', rawdata[4]);
254         assertEquals('\n', rawdata[5]);
255         assertEquals('0', rawdata[6]);
256         assertEquals('\r', rawdata[7]);
257         assertEquals('\n', rawdata[8]);
258         assertEquals('\r', rawdata[9]);
259         assertEquals('\n', rawdata[10]);
260     }
261 
262     // ------------------------------------------------------- TestCase Methods
263 
264     public static Test suite() {
265         return new TestSuite(TestStreams.class);
266     }
267 
268     // ------------------------------------------------------------------- Main
269     public static void main(String args[]) {
270         String[] testCaseName = { TestStreams.class.getName() };
271         junit.textui.TestRunner.main(testCaseName);
272     }
273 
274 
275     public void testAutoCloseInputStream() throws IOException {
276         // The purpose of this test is to check EOF handling of ACIS with
277         // respect to exceptions being thrown. Putting it on top of a
278         // plain ByteArrayInputStream won't do, since BAIS can't be closed.
279         ByteArrayInputStream bais =
280             new ByteArrayInputStream("whatever".getBytes());
281         InputStream fbais = new java.io.FilterInputStream(bais) {
282                 private boolean closed = false;
283                 public void close() throws IOException {
284                     closed = true;
285                     super.close();
286                 }
287                 public int available() throws IOException {
288                     if (closed)
289                         throw new IOException("closed");
290                     return super.available();
291                 }
292             };
293 
294         AutoCloseInputStream acis = new AutoCloseInputStream(fbais, null);
295         byte[] data = new byte[16];
296         int count = 0;
297         while (count >= 0) {
298             count = acis.read(data);
299         }
300         // We're at EOF. The underlying stream should be closed,
301         // but the ACIS itself not.
302         try {
303             fbais.available();
304             fail("underlying stream not auto-closed");
305         } catch (IOException x) {
306             // expected, pis should be closed
307         }
308 
309         // don't want to see an exception being thrown here
310         acis.available();
311 
312         acis.close();
313         try {
314             acis.available();
315             fail("auto-close stream not closed");
316         } catch (IOException x) {
317             // expected, acis should be closed
318         }
319     }
320 }
321