View Javadoc
1 /* 2 * $Header: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/ResponseInputStream.java,v 1.23 2003/02/12 13:21:27 olegk Exp $ 3 * $Revision: 1.23 $ 4 * $Date: 2003/02/12 13:21:27 $ 5 * 6 * ==================================================================== 7 * 8 * The Apache Software License, Version 1.1 9 * 10 * Copyright (c) 1999-2003 The Apache Software Foundation. All rights 11 * reserved. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 20 * 2. Redistributions in binary form must reproduce the above copyright 21 * notice, this list of conditions and the following disclaimer in 22 * the documentation and/or other materials provided with the 23 * distribution. 24 * 25 * 3. The end-user documentation included with the redistribution, if 26 * any, must include the following acknowlegement: 27 * "This product includes software developed by the 28 * Apache Software Foundation (http://www.apache.org/)." 29 * Alternately, this acknowlegement may appear in the software itself, 30 * if and wherever such third-party acknowlegements normally appear. 31 * 32 * 4. The names "The Jakarta Project", "Commons", and "Apache Software 33 * Foundation" must not be used to endorse or promote products derived 34 * from this software without prior written permission. For written 35 * permission, please contact apache@apache.org. 36 * 37 * 5. Products derived from this software may not be called "Apache" 38 * nor may "Apache" appear in their names without prior written 39 * permission of the Apache Group. 40 * 41 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 42 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 43 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 44 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 45 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 46 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 47 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 48 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 49 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 50 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 51 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 52 * SUCH DAMAGE. 53 * ==================================================================== 54 * 55 * This software consists of voluntary contributions made by many 56 * individuals on behalf of the Apache Software Foundation. For more 57 * information on the Apache Software Foundation, please see 58 * <http://www.apache.org/>. 59 * 60 * [Additional notices, if required by prior licensing conditions] 61 * 62 */ 63 64 package org.apache.commons.httpclient; 65 66 import java.io.IOException; 67 import java.io.InputStream; 68 69 import org.apache.commons.logging.LogFactory; 70 import org.apache.commons.logging.Log; 71 72 /*** 73 * <p>{@link InputStream} wrapper supporting the chunked transfer encoding.</p> 74 * 75 * @author <a href="mailto:remm@apache.org">Remy Maucherat</a> 76 * @author Sean C. Sullivan 77 * @author <a href="mailto:dion@apache.org">dIon Gillard</a> 78 * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a> 79 * @version $Revision: 1.23 $ $Date: 2003/02/12 13:21:27 $ 80 * 81 * @deprecated Use new ChunkedInputStream(HttpConnecion#getResponseInputStream()); 82 * 83 */ 84 public class ResponseInputStream extends InputStream { 85 86 // -------------------------------------------------------- Class Variables 87 88 /*** Log object for this class. */ 89 public static final Log LOG = LogFactory.getLog(ResponseInputStream.class); 90 91 // ----------------------------------------------------------- Constructors 92 93 /*** 94 * 95 * @param stream Must be non-null. 96 * @param chunked <code>true</code> if the input stream is chunked 97 * @param contentLength content length 98 * 99 * @deprecated Use ChunkedInputStream; 100 */ 101 public ResponseInputStream(InputStream stream, boolean chunked, int contentLength) { 102 LOG.trace("enter ResponseInputStream(InputStream, boolean, int)"); 103 104 if (null == stream) { 105 throw new NullPointerException("InputStream parameter is null"); 106 } 107 closed = false; 108 count = 0; 109 this.chunk = chunked; 110 this.contentLength = contentLength; 111 this.stream = stream; 112 } 113 114 /*** 115 * Construct a servlet input stream associated with the specified Request. 116 * 117 * @param stream Must be non-null. 118 * @param method Must be non-null. 119 * 120 * @deprecated Use ChunkedInputStream; 121 * 122 */ 123 public ResponseInputStream(InputStream stream, HttpMethod method) { 124 super(); 125 LOG.trace("enter ResponseInputStream(InputStream, HttpMethod)"); 126 127 if (null == stream) { 128 throw new NullPointerException("InputStream parameter is null"); 129 } 130 131 if (null == method) { 132 throw new NullPointerException("HttpMethod parameter is null"); 133 } 134 135 closed = false; 136 count = 0; 137 138 // Retrieving transfer encoding header 139 Header transferEncoding = method.getResponseHeader("transfer-encoding"); 140 if ((null != transferEncoding) && (transferEncoding.getValue(). 141 toLowerCase().indexOf("chunked") != -1)) { 142 chunk = true; 143 } 144 145 // Retrieving content length header 146 Header contentLengthHeader = method.getResponseHeader("content-length"); 147 if (null != contentLengthHeader) { 148 try { 149 this.contentLength = 150 Integer.parseInt(contentLengthHeader.getValue()); 151 } catch (NumberFormatException ignored) { 152 // we are intentionally ignoring the NumberFormatException 153 } 154 } 155 156 this.stream = stream; 157 } 158 159 160 // ----------------------------------------------------- Instance Variables 161 162 /*** 163 * Has this stream been closed? 164 */ 165 private boolean closed = false; 166 167 /*** 168 * Use chunking ? 169 */ 170 private boolean chunk = false; 171 172 /*** 173 * True if the final chunk was found. 174 */ 175 private boolean endChunk = false; 176 177 /*** 178 * Chunk buffer. 179 */ 180 private byte[] buffer = null; 181 182 /*** 183 * Current chunk length. 184 */ 185 private int length = 0; 186 187 /*** 188 * Current chunk buffer position. 189 */ 190 private int pos = 0; 191 192 /*** 193 * The number of bytes which have already been returned by this stream. 194 */ 195 private int count = 0; 196 197 /*** 198 * The content length past which we will not read, or -1 if there is 199 * no defined content length. 200 */ 201 private int contentLength = -1; 202 203 /*** 204 * The underlying input stream from which we should read data. 205 */ 206 private InputStream stream = null; 207 208 // --------------------------------------------------------- Public Methods 209 210 /*** 211 * Close this input stream. No physical level I-O is performed, but 212 * any further attempt to read from this stream will throw an IOException. 213 * If a content length has been set but not all of the bytes have yet been 214 * consumed, the remaining bytes will be swallowed. 215 * 216 * @throws IOException If an IO problem occurs. 217 * 218 * @deprecated Use ChunkedInputStream; 219 */ 220 public void close() throws IOException { 221 LOG.trace("enter ResponseInputStream.close()"); 222 /* 223 // Xerces appears to doubly-close the input stream... 224 if(closed) { 225 throw new IOException("Stream is already closed"); 226 } 227 */ 228 229 //TODO: This close code is not very robust 230 if (!closed) { 231 try { 232 if (chunk) { 233 while (!endChunk) { 234 int b = read(); 235 if (b < 0) { 236 break; 237 } 238 } 239 } else { 240 if (length > 0) { 241 while (count < length) { 242 int b = read(); 243 if (b < 0) { 244 break; 245 } 246 } 247 } 248 } 249 } catch (java.io.IOException ex) { 250 throw ex; 251 } finally { 252 closed = true; 253 } 254 } 255 } 256 257 258 /*** 259 * Read up to <code>len</code> bytes of data from the input stream 260 * into an array of bytes. An attempt is made to read as many as 261 * <code>len</code> bytes, but a smaller number may be read, 262 * possibly zero. The number of bytes actually read is returned as 263 * an integer. This method blocks until input data is available, 264 * end of file is detected, or an exception is thrown. 265 * 266 * @param b The buffer into which the data is read 267 * @param off The start offset into array <code>b</code> at which 268 * the data is written 269 * @param len The maximum number of bytes to read 270 * @return The number of bytes that were read. 271 * 272 * @exception IOException if an input/output error occurs 273 * 274 * @deprecated Use ChunkedInputStream; 275 */ 276 public int read(byte b[], int off, int len) 277 throws IOException { 278 LOG.trace("enter ResponseInputStream.read(byte, int, int)"); 279 280 int avail = length - pos; 281 if ((avail == 0) && (!fillBuffer())) { 282 return (-1); 283 } 284 285 avail = length - pos; 286 if (avail == 0) { 287 return (-1); 288 } 289 290 int toCopy = avail; 291 292 if (toCopy < 0) { 293 return (-1); 294 } 295 296 if (avail > len) { 297 toCopy = len; 298 } 299 System.arraycopy(buffer, pos, b, off, toCopy); 300 pos += toCopy; 301 return toCopy; 302 } 303 304 /*** 305 * Read and return a single byte from this input stream, or -1 if end of 306 * file has been encountered. 307 * 308 * @return The next byte in the stream or -1. 309 * @exception IOException if an input/output error occurs 310 * 311 * @deprecated Use ChunkedInputStream; 312 */ 313 public int read() throws IOException { 314 LOG.trace("enter ResponseInputStream.read()"); 315 316 if (pos == length) { 317 if (!fillBuffer()) { 318 return (-1); 319 } 320 } 321 322 return (buffer[pos++] & 0xff); 323 324 } 325 326 // -------------------------------------------------------- Private Methods 327 328 329 /*** 330 * Fill the chunk buffer. 331 * @return true If successful 332 * @throws IOException If an IO problem occurs. 333 * 334 * @deprecated Use ChunkedInputStream; 335 */ 336 private boolean fillBuffer() throws IOException { 337 LOG.trace("enter ResponseInputStream.fillBuffer()"); 338 339 // Has this stream been closed? 340 if (closed) { 341 return false; 342 } 343 //throw new IOException("Stream is closed"); 344 345 if (endChunk) { 346 return false; 347 } 348 349 // Have we read the specified content length already? 350 if ((contentLength >= 0) && (count >= contentLength)) { 351 return false; // End of file indicator 352 } 353 354 pos = 0; 355 356 if (chunk) { 357 358 try { 359 String numberValue = readLineFromStream(); 360 if (numberValue == null) { 361 throw new NumberFormatException("unable to find chunk length"); 362 } 363 364 length = Integer.parseInt(numberValue.trim(), 16); 365 } catch (NumberFormatException e) { 366 // Critical error, unable to parse the chunk length 367 length = -1; 368 chunk = false; 369 endChunk = true; 370 closed = true; 371 return false; 372 } 373 374 if (length == 0) { 375 376 // Skipping trailing headers, if any 377 String trailingLine = readLineFromStream(); 378 while (!trailingLine.equals("")) { 379 trailingLine = readLineFromStream(); 380 } 381 endChunk = true; 382 return false; 383 384 } else { 385 386 if ((buffer == null) || (length > buffer.length)) { 387 buffer = new byte[length]; 388 } 389 390 // Now read the whole chunk into the buffer 391 392 int nbRead = 0; 393 int currentRead = 0; 394 395 while (nbRead < length) { 396 try { 397 currentRead = stream.read(buffer, nbRead, 398 length - nbRead); 399 } catch (Throwable t) { 400 LOG.debug("Exception thrown reading chunk from response", t); 401 throw new IOException(); 402 } 403 if (currentRead < 0) { 404 throw new IOException("Not enough bytes read"); 405 } 406 nbRead += currentRead; 407 } 408 409 // Skipping the CRLF 410 readLineFromStream(); 411 412 } 413 414 } else { //not using chunking 415 416 try { 417 if (buffer == null) { 418 buffer = new byte[4096]; 419 } 420 length = stream.read(buffer); 421 count += length; 422 } catch (Throwable t) { 423 LOG.debug("Exception thrown reading from response", t); 424 throw new IOException(t.getMessage()); 425 } 426 427 } 428 429 return true; 430 431 } 432 433 /*** 434 * Reads the input stream, one line at a time. Reads bytes into an array, 435 * until it reads a certain number of bytes or reaches a newline character, 436 * which it reads into the array as well. 437 * 438 * @return The line that was read, or <code>null</code> if end-of-file 439 * was encountered 440 * @exception IOException if an input or output exception has occurred 441 * 442 * @deprecated Use ChunkedInputStream; 443 */ 444 private String readLineFromStream() 445 throws IOException { 446 LOG.trace("enter ResponseInputStream.ReadLineFromStream()"); 447 448 StringBuffer sb = new StringBuffer(); 449 while (true) { 450 int ch = stream.read(); 451 if (ch < 0) { 452 if (sb.length() == 0) { 453 return (null); 454 } else { 455 break; 456 } 457 } else if (ch == '\r') { 458 continue; 459 } else if (ch == '\n') { 460 break; 461 } 462 sb.append((char) ch); 463 } 464 return (sb.toString()); 465 } 466 }

This page was automatically generated by Maven