KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > commons > httpclient > ResponseInputStream


1 /*
2  * $Header: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/Attic/ResponseInputStream.java,v 1.23.2.1 2004/02/22 18:21:13 olegk Exp $
3  * $Revision: 1.23.2.1 $
4  * $Date: 2004/02/22 18:21:13 $
5  *
6  * ====================================================================
7  *
8  * Copyright 1999-2004 The Apache Software Foundation
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * 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.IOException JavaDoc;
35 import java.io.InputStream JavaDoc;
36
37 import org.apache.commons.logging.LogFactory;
38 import org.apache.commons.logging.Log;
39
40 /**
41  * <p>{@link InputStream} wrapper supporting the chunked transfer encoding.</p>
42  *
43  * @author <a HREF="mailto:remm@apache.org">Remy Maucherat</a>
44  * @author Sean C. Sullivan
45  * @author <a HREF="mailto:dion@apache.org">dIon Gillard</a>
46  * @author <a HREF="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
47  * @version $Revision: 1.23.2.1 $ $Date: 2004/02/22 18:21:13 $
48  *
49  * @deprecated Use new ChunkedInputStream(HttpConnecion#getResponseInputStream());
50  *
51  */

52 public class ResponseInputStream extends InputStream JavaDoc {
53
54     // -------------------------------------------------------- Class Variables
55

56     /** Log object for this class. */
57     public static final Log LOG = LogFactory.getLog(ResponseInputStream.class);
58
59     // ----------------------------------------------------------- Constructors
60

61     /**
62      *
63      * @param stream Must be non-null.
64      * @param chunked <code>true</code> if the input stream is chunked
65      * @param contentLength content length
66      *
67      * @deprecated Use ChunkedInputStream;
68      */

69     public ResponseInputStream(InputStream JavaDoc stream, boolean chunked, int contentLength) {
70         LOG.trace("enter ResponseInputStream(InputStream, boolean, int)");
71
72         if (null == stream) {
73             throw new NullPointerException JavaDoc("InputStream parameter is null");
74         }
75         closed = false;
76         count = 0;
77         this.chunk = chunked;
78         this.contentLength = contentLength;
79         this.stream = stream;
80     }
81
82     /**
83      * Construct a servlet input stream associated with the specified Request.
84      *
85      * @param stream Must be non-null.
86      * @param method Must be non-null.
87      *
88      * @deprecated Use ChunkedInputStream;
89      *
90      */

91     public ResponseInputStream(InputStream JavaDoc stream, HttpMethod method) {
92         super();
93         LOG.trace("enter ResponseInputStream(InputStream, HttpMethod)");
94
95         if (null == stream) {
96             throw new NullPointerException JavaDoc("InputStream parameter is null");
97         }
98
99         if (null == method) {
100             throw new NullPointerException JavaDoc("HttpMethod parameter is null");
101         }
102
103         closed = false;
104         count = 0;
105
106         // Retrieving transfer encoding header
107
Header transferEncoding = method.getResponseHeader("transfer-encoding");
108         if ((null != transferEncoding) && (transferEncoding.getValue().
109                              toLowerCase().indexOf("chunked") != -1)) {
110             chunk = true;
111         }
112
113         // Retrieving content length header
114
Header contentLengthHeader = method.getResponseHeader("content-length");
115         if (null != contentLengthHeader) {
116             try {
117                 this.contentLength =
118                     Integer.parseInt(contentLengthHeader.getValue());
119             } catch (NumberFormatException JavaDoc ignored) {
120                    // we are intentionally ignoring the NumberFormatException
121
}
122         }
123
124         this.stream = stream;
125     }
126
127
128     // ----------------------------------------------------- Instance Variables
129

130     /**
131      * Has this stream been closed?
132      */

133     private boolean closed = false;
134
135     /**
136      * Use chunking ?
137      */

138     private boolean chunk = false;
139
140     /**
141      * True if the final chunk was found.
142      */

143     private boolean endChunk = false;
144
145     /**
146      * Chunk buffer.
147      */

148     private byte[] buffer = null;
149
150     /**
151      * Current chunk length.
152      */

153     private int length = 0;
154
155     /**
156      * Current chunk buffer position.
157      */

158     private int pos = 0;
159
160     /**
161      * The number of bytes which have already been returned by this stream.
162      */

163     private int count = 0;
164
165     /**
166      * The content length past which we will not read, or -1 if there is
167      * no defined content length.
168      */

169     private int contentLength = -1;
170
171     /**
172      * The underlying input stream from which we should read data.
173      */

174     private InputStream JavaDoc stream = null;
175
176     // --------------------------------------------------------- Public Methods
177

178     /**
179      * Close this input stream. No physical level I-O is performed, but
180      * any further attempt to read from this stream will throw an IOException.
181      * If a content length has been set but not all of the bytes have yet been
182      * consumed, the remaining bytes will be swallowed.
183      *
184      * @throws IOException If an IO problem occurs.
185      *
186      * @deprecated Use ChunkedInputStream;
187      */

188     public void close() throws IOException JavaDoc {
189         LOG.trace("enter ResponseInputStream.close()");
190     /*
191         // Xerces appears to doubly-close the input stream...
192         if(closed) {
193             throw new IOException("Stream is already closed");
194         }
195     */

196
197         //TODO: This close code is not very robust
198
if (!closed) {
199             try {
200                 if (chunk) {
201                     while (!endChunk) {
202                         int b = read();
203                         if (b < 0) {
204                             break;
205                         }
206                     }
207                 } else {
208                     if (length > 0) {
209                         while (count < length) {
210                             int b = read();
211                             if (b < 0) {
212                                 break;
213                             }
214                         }
215                     }
216                 }
217             } catch (java.io.IOException JavaDoc ex) {
218                 throw ex;
219             } finally {
220                     closed = true;
221             }
222         }
223     }
224
225
226     /**
227      * Read up to <code>len</code> bytes of data from the input stream
228      * into an array of bytes. An attempt is made to read as many as
229      * <code>len</code> bytes, but a smaller number may be read,
230      * possibly zero. The number of bytes actually read is returned as
231      * an integer. This method blocks until input data is available,
232      * end of file is detected, or an exception is thrown.
233      *
234      * @param b The buffer into which the data is read
235      * @param off The start offset into array <code>b</code> at which
236      * the data is written
237      * @param len The maximum number of bytes to read
238      * @return The number of bytes that were read.
239      *
240      * @exception IOException if an input/output error occurs
241      *
242      * @deprecated Use ChunkedInputStream;
243      */

244     public int read(byte b[], int off, int len)
245     throws IOException JavaDoc {
246         LOG.trace("enter ResponseInputStream.read(byte, int, int)");
247
248         int avail = length - pos;
249         if ((avail == 0) && (!fillBuffer())) {
250             return (-1);
251         }
252
253         avail = length - pos;
254         if (avail == 0) {
255             return (-1);
256         }
257
258         int toCopy = avail;
259
260         if (toCopy < 0) {
261           return (-1);
262         }
263
264         if (avail > len) {
265             toCopy = len;
266         }
267         System.arraycopy(buffer, pos, b, off, toCopy);
268         pos += toCopy;
269         return toCopy;
270     }
271
272     /**
273      * Read and return a single byte from this input stream, or -1 if end of
274      * file has been encountered.
275      *
276      * @return The next byte in the stream or -1.
277      * @exception IOException if an input/output error occurs
278      *
279      * @deprecated Use ChunkedInputStream;
280      */

281     public int read() throws IOException JavaDoc {
282         LOG.trace("enter ResponseInputStream.read()");
283
284         if (pos == length) {
285             if (!fillBuffer()) {
286                 return (-1);
287             }
288         }
289
290         return (buffer[pos++] & 0xff);
291
292     }
293
294     // -------------------------------------------------------- Private Methods
295

296
297     /**
298      * Fill the chunk buffer.
299      * @return true If successful
300      * @throws IOException If an IO problem occurs.
301      *
302      * @deprecated Use ChunkedInputStream;
303      */

304     private boolean fillBuffer() throws IOException JavaDoc {
305         LOG.trace("enter ResponseInputStream.fillBuffer()");
306
307         // Has this stream been closed?
308
if (closed) {
309             return false;
310         }
311             //throw new IOException("Stream is closed");
312

313         if (endChunk) {
314             return false;
315         }
316
317         // Have we read the specified content length already?
318
if ((contentLength >= 0) && (count >= contentLength)) {
319             return false; // End of file indicator
320
}
321
322         pos = 0;
323
324         if (chunk) {
325
326             try {
327                 String JavaDoc numberValue = readLineFromStream();
328                 if (numberValue == null) {
329                   throw new NumberFormatException JavaDoc("unable to find chunk length");
330                 }
331
332                 length = Integer.parseInt(numberValue.trim(), 16);
333             } catch (NumberFormatException JavaDoc e) {
334                 // Critical error, unable to parse the chunk length
335
length = -1;
336                 chunk = false;
337                 endChunk = true;
338                 closed = true;
339                 return false;
340             }
341
342             if (length == 0) {
343
344                 // Skipping trailing headers, if any
345
String JavaDoc trailingLine = readLineFromStream();
346                 while (!trailingLine.equals("")) {
347                     trailingLine = readLineFromStream();
348                 }
349                 endChunk = true;
350                 return false;
351
352             } else {
353
354                 if ((buffer == null) || (length > buffer.length)) {
355                     buffer = new byte[length];
356                 }
357
358                 // Now read the whole chunk into the buffer
359

360                 int nbRead = 0;
361                 int currentRead = 0;
362
363                 while (nbRead < length) {
364                     try {
365                         currentRead = stream.read(buffer, nbRead,
366                                         length - nbRead);
367                     } catch (Throwable JavaDoc t) {
368                         LOG.debug("Exception thrown reading chunk from response", t);
369                         throw new IOException JavaDoc();
370                     }
371                     if (currentRead < 0) {
372                         throw new IOException JavaDoc("Not enough bytes read");
373                     }
374                     nbRead += currentRead;
375                 }
376
377                 // Skipping the CRLF
378
readLineFromStream();
379
380             }
381
382         } else { //not using chunking
383

384             try {
385                 if (buffer == null) {
386                     buffer = new byte[4096];
387                 }
388                 length = stream.read(buffer);
389                 count += length;
390             } catch (Throwable JavaDoc t) {
391                 LOG.debug("Exception thrown reading from response", t);
392                 throw new IOException JavaDoc(t.getMessage());
393             }
394
395         }
396
397         return true;
398
399     }
400
401     /**
402      * Reads the input stream, one line at a time. Reads bytes into an array,
403      * until it reads a certain number of bytes or reaches a newline character,
404      * which it reads into the array as well.
405      *
406      * @return The line that was read, or <code>null</code> if end-of-file
407      * was encountered
408      * @exception IOException if an input or output exception has occurred
409      *
410      * @deprecated Use ChunkedInputStream;
411      */

412     private String JavaDoc readLineFromStream()
413     throws IOException JavaDoc {
414         LOG.trace("enter ResponseInputStream.ReadLineFromStream()");
415
416         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
417         while (true) {
418             int ch = stream.read();
419             if (ch < 0) {
420                 if (sb.length() == 0) {
421                     return (null);
422                 } else {
423                     break;
424                 }
425             } else if (ch == '\r') {
426                 continue;
427             } else if (ch == '\n') {
428                 break;
429             }
430             sb.append((char) ch);
431         }
432         return (sb.toString());
433     }
434 }
435
Popular Tags