001: /*
002: * HttpInputStream.java
003: *
004: * Brazil project web application Framework,
005: * export version: 1.1
006: * Copyright (c) 1999-2000 Sun Microsystems, Inc.
007: *
008: * Sun Public License Notice
009: *
010: * The contents of this file are subject to the Sun Public License Version
011: * 1.0 (the "License"). You may not use this file except in compliance with
012: * the License. A copy of the License is included as the file "license.terms",
013: * and also available at http://www.sun.com/
014: *
015: * The Original Code is from:
016: * Brazil project web application Framework release 1.1.
017: * The Initial Developer of the Original Code is: cstevens.
018: * Portions created by cstevens are Copyright (C) Sun Microsystems, Inc.
019: * All Rights Reserved.
020: *
021: * Contributor(s): cstevens.
022: *
023: * Version: 1.7
024: * Created by cstevens on 99/09/15
025: * Last modified by cstevens on 00/03/29 16:47:15
026: */
027:
028: package sunlabs.brazil.util.http;
029:
030: import java.io.FilterInputStream;
031: import java.io.IOException;
032: import java.io.InputStream;
033: import java.io.OutputStream;
034: import java.io.PushbackInputStream;
035:
036: /**
037: * This class is an input stream that provides added methods that are
038: * of help when reading the result of an HTTP request. By setting up
039: * this input stream, the user can conveniently read lines of text and
040: * copy the contents of an input stream to an output stream.
041: * <p>
042: * The underlying assumption of this class is that when reading the result
043: * of an HTTP request, each byte in the input stream represents an 8-bit
044: * ASCII character, and as such, it is perfectly valid to treat each byte
045: * as a character. Locale-based conversion is not appropriate in this
046: * circumstance, so the <code>java.io.BufferedReader.readLine</code> method
047: * should not be used.
048: *
049: * @author Colin Stevens (colin.stevens@sun.com)
050: * @version 1.7, 00/03/29
051: */
052: public class HttpInputStream extends FilterInputStream {
053: /**
054: * The default size of the temporary buffer used when copying from an
055: * input stream to an output stream.
056: *
057: * @see #copyTo(OutputStream, int, byte[])
058: */
059: public static int defaultBufsize = 4096;
060:
061: /**
062: * Creates a new HttpInputStream that reads its input from the
063: * specified input stream.
064: *
065: * @param in
066: * The underlying input stream.
067: */
068: public HttpInputStream(InputStream in) {
069: super (in);
070: }
071:
072: /**
073: * Reads the next line of text from the input stream.
074: * <p>
075: * A line is terminated by "\r", "\n", "\r\n", or the end of the input
076: * stream. The line-terminating characters are discarded.
077: *
078: * @return The next line from the input stream, or <code>null</code>
079: * if the end of the input stream is reached and no bytes
080: * were found.
081: *
082: * @throws IOException if the underlying input stream throws an
083: * IOException while being read.
084: */
085: public String readLine() throws IOException {
086: return readLine(Integer.MAX_VALUE);
087: }
088:
089: /**
090: * Reads the next line of text from the input stream, up to the
091: * limit specified.
092: * <p>
093: * A line is terminated by "\r", "\n", "\r\n", the end of the input
094: * stream, or when the specified number of characters have been read.
095: * The line-terminating characters are discarded. It is not possible
096: * to distinguish, based on the result, between a line that was
097: * exactly <code>limit</code> characters long and a line that was
098: * terminated because <code>limit</code> characters were read.
099: *
100: * @return The next line from the input stream, or <code>null</code>
101: * if the end of the input stream is reached and no bytes
102: * were found.
103: *
104: * @throws IOException if the underlying input stream throws an
105: * IOException while being read.
106: */
107: public String readLine(int limit) throws IOException {
108: StringBuffer sb = new StringBuffer();
109:
110: while (limit-- > 0) {
111: int ch = read();
112: if (ch == '\r') {
113: ch = read();
114: if (ch != '\n') {
115: if ((in instanceof PushbackInputStream) == false) {
116: in = new PushbackInputStream(in);
117: }
118: ((PushbackInputStream) in).unread(ch);
119: }
120: break;
121: } else if (ch == '\n') {
122: break;
123: } else if (ch < 0) {
124: if (sb.length() == 0) {
125: return null;
126: }
127: break;
128: } else {
129: sb.append((char) ch);
130: }
131: }
132: return sb.toString();
133: }
134:
135: /**
136: * Reads <code>buf.length</code> bytes from the input stream. This
137: * method reads repeatedly from the input stream until the specified
138: * number of bytes have been read or the end of the input stream
139: * is reached.
140: * <p>
141: * The standard <code>InputStream.read</code> method will generally
142: * return less than the specified number of bytes if the underlying
143: * input stream is "bursty", such as from a network source. Sometimes
144: * it is important to read the exact number of bytes desired.
145: *
146: * @param buf
147: * Buffer in which the data is stored. If buffer is of
148: * length 0, this method will return immediately.
149: *
150: * @return The number of bytes read. This will be less than
151: * <code>buf.length</code> if the end of the input stream was
152: * reached.
153: *
154: * @throws IOException if the underlying input stream throws an
155: * IOException while being read.
156: */
157: public int readFully(byte[] buf) throws IOException {
158: return readFully(buf, 0, buf.length);
159: }
160:
161: /**
162: * Reads the specified number of bytes from the input stream. This
163: * method reads repeatedly from the input stream until the specified
164: * number of bytes have been read or the end of the input stream is
165: * reached.
166: * <p>
167: * The standard <code>InputStream.read</code> method will generally
168: * return less than the specified number of bytes if the underlying
169: * input stream is "bursty", such as from a network source. Sometimes
170: * it is important to read the exact number of bytes desired.
171: *
172: * @param buf
173: * Buffer in which the data is stored.
174: *
175: * @param off
176: * The starting offset into the buffer.
177: *
178: * @param len
179: * The number of bytes to read.
180: *
181: * @return The number of bytes read. This will be less than
182: * <code>len</code> if the end of the input stream was reached.
183: *
184: * @throws IOException if the underlying input stream throws an
185: * IOException while being read.
186: */
187: public int readFully(byte[] buf, int off, int len)
188: throws IOException {
189: int total = 0;
190:
191: while (len > 0) {
192: int count = read(buf, off, len);
193: if (count < 0) {
194: break;
195: }
196: total += count;
197: off += count;
198: len -= count;
199: }
200:
201: return total;
202: }
203:
204: /**
205: * Copies bytes from this input stream to the specified output stream
206: * until end of the input stream is reached.
207: *
208: * @param out
209: * The output stream to copy the data to.
210: *
211: * @return The number of bytes copied to the output stream.
212: *
213: * @throws IOException if the underlying input stream throws an
214: * IOException while being read or if the output stream
215: * throws an IOException while being written. It may not be
216: * possible to distinguish amongst the two conditions.
217: */
218: public int copyTo(OutputStream out) throws IOException {
219: return copyTo(out, -1, null);
220: }
221:
222: /**
223: * Copies bytes from this input stream to the specified output stream
224: * until the specified number of bytes are copied or the end of the
225: * input stream is reached.
226: *
227: * @param out
228: * The output stream to copy the data to.
229: *
230: * @param len
231: * The number of bytes to copy, or < 0 to copy until the end
232: * of this stream.
233: *
234: * @return The number of bytes copied to the output stream.
235: *
236: * @throws IOException if the underlying input stream throws an
237: * IOException while being read or if the output stream
238: * throws an IOException while being written. It may not be
239: * possible to distinguish amongst the two conditions.
240: */
241: public int copyTo(OutputStream out, int len) throws IOException {
242: return copyTo(out, len, null);
243: }
244:
245: /**
246: * Copies bytes from this input stream to the specified output stream
247: * until the specified number of bytes are copied or the end of the
248: * input stream is reached.
249: *
250: * @param out
251: * The output stream to copy the data to.
252: *
253: * @param len
254: * The number of bytes to copy, or < 0 to copy until the end
255: * of this stream.
256: *
257: * @param buf
258: * The buffer used to for holding the temporary results while
259: * copying data from this input stream to the output stream.
260: * May be <code>null</code> to allow this method copy in
261: * chunks of length <code>defaultBufsize</code>.
262: *
263: * @return The number of bytes copied to the output stream.
264: *
265: * @throws IOException if the underlying input stream throws an
266: * IOException while being read or if the output stream
267: * throws an IOException while being written. It may not be
268: * possible to distinguish amongst the two conditions.
269: */
270: public int copyTo(OutputStream out, int len, byte[] buf)
271: throws IOException {
272: if (len < 0) {
273: len = Integer.MAX_VALUE;
274: }
275: if (buf == null) {
276: buf = new byte[Math.min(defaultBufsize, len)];
277: }
278:
279: int total = 0;
280: while (len > 0) {
281: int count = read(buf, 0, Math.min(buf.length, len));
282: if (count < 0) {
283: break;
284: }
285: out.write(buf, 0, count);
286:
287: /*
288: * For streaming media to work, must flush output buffer
289: * to client whenever we get any data.
290: */
291: out.flush();
292: total += count;
293: len -= count;
294: }
295: return total;
296: }
297: }
|