1. /*
  2. * $Header: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/ContentLengthInputStream.java,v 1.11 2004/08/09 01:25:54 mbecke Exp $
  3. * $Revision: 1.11 $
  4. * $Date: 2004/08/09 01:25:54 $
  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. */
  29. package org.apache.commons.httpclient;
  30. import java.io.FilterInputStream;
  31. import java.io.IOException;
  32. import java.io.InputStream;
  33. /**
  34. * Cuts the wrapped InputStream off after a specified number of bytes.
  35. *
  36. * @author Ortwin Gl???ck
  37. * @author Eric Johnson
  38. * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
  39. * @since 2.0
  40. */
  41. public class ContentLengthInputStream extends FilterInputStream {
  42. /**
  43. * The maximum number of bytes that can be read from the stream. Subsequent
  44. * read operations will return -1.
  45. */
  46. private long contentLength;
  47. /** The current position */
  48. private long pos = 0;
  49. /** True if the stream is closed. */
  50. private boolean closed = false;
  51. /**
  52. * @deprecated use {@link #ContentLengthInputStream(InputStream, long)}
  53. *
  54. * Creates a new length limited stream
  55. *
  56. * @param in The stream to wrap
  57. * @param contentLength The maximum number of bytes that can be read from
  58. * the stream. Subsequent read operations will return -1.
  59. */
  60. public ContentLengthInputStream(InputStream in, int contentLength) {
  61. super(in);
  62. this.contentLength = contentLength;
  63. }
  64. /**
  65. * Creates a new length limited stream
  66. *
  67. * @param in The stream to wrap
  68. * @param contentLength The maximum number of bytes that can be read from
  69. * the stream. Subsequent read operations will return -1.
  70. *
  71. * @since 3.0
  72. */
  73. public ContentLengthInputStream(InputStream in, long contentLength) {
  74. super(in);
  75. this.contentLength = contentLength;
  76. }
  77. /**
  78. * <p>Reads until the end of the known length of content.</p>
  79. *
  80. * <p>Does not close the underlying socket input, but instead leaves it
  81. * primed to parse the next response.</p>
  82. * @throws IOException If an IO problem occurs.
  83. */
  84. public void close() throws IOException {
  85. if (!closed) {
  86. try {
  87. ChunkedInputStream.exhaustInputStream(this);
  88. } finally {
  89. // close after above so that we don't throw an exception trying
  90. // to read after closed!
  91. closed = true;
  92. }
  93. }
  94. }
  95. /**
  96. * Read the next byte from the stream
  97. * @return The next byte or -1 if the end of stream has been reached.
  98. * @throws IOException If an IO problem occurs
  99. * @see java.io.InputStream#read()
  100. */
  101. public int read() throws IOException {
  102. if (closed) {
  103. throw new IOException("Attempted read from closed stream.");
  104. }
  105. if (pos >= contentLength) {
  106. return -1;
  107. }
  108. pos++;
  109. return super.read();
  110. }
  111. /**
  112. * Does standard {@link InputStream#read(byte[], int, int)} behavior, but
  113. * also notifies the watcher when the contents have been consumed.
  114. *
  115. * @param b The byte array to fill.
  116. * @param off Start filling at this position.
  117. * @param len The number of bytes to attempt to read.
  118. * @return The number of bytes read, or -1 if the end of content has been
  119. * reached.
  120. *
  121. * @throws java.io.IOException Should an error occur on the wrapped stream.
  122. */
  123. public int read (byte[] b, int off, int len) throws java.io.IOException {
  124. if (closed) {
  125. throw new IOException("Attempted read from closed stream.");
  126. }
  127. if (pos >= contentLength) {
  128. return -1;
  129. }
  130. if (pos + len > contentLength) {
  131. len = (int) (contentLength - pos);
  132. }
  133. int count = super.read(b, off, len);
  134. pos += count;
  135. return count;
  136. }
  137. /**
  138. * Read more bytes from the stream.
  139. * @param b The byte array to put the new data in.
  140. * @return The number of bytes read into the buffer.
  141. * @throws IOException If an IO problem occurs
  142. * @see java.io.InputStream#read(byte[])
  143. */
  144. public int read(byte[] b) throws IOException {
  145. return read(b, 0, b.length);
  146. }
  147. /**
  148. * Skips and discards a number of bytes from the input stream.
  149. * @param n The number of bytes to skip.
  150. * @return The actual number of bytes skipped. <= 0 if no bytes
  151. * are skipped.
  152. * @throws IOException If an error occurs while skipping bytes.
  153. * @see InputStream#skip(long)
  154. */
  155. public long skip(long n) throws IOException {
  156. // make sure we don't skip more bytes than are
  157. // still available
  158. long length = Math.min(n, contentLength - pos);
  159. // skip and keep track of the bytes actually skipped
  160. length = super.skip(length);
  161. // only add the skipped bytes to the current position
  162. // if bytes were actually skipped
  163. if (length > 0) {
  164. pos += length;
  165. }
  166. return length;
  167. }
  168. }