View Javadoc

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