1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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
99
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 }