001: // Copyright (C) 1999-2001 by Jason Hunter <jhunter_AT_acm_DOT_org>.
002: // All rights reserved. Use of this class is limited.
003: // Please see the LICENSE for more information.
004:
005: package com.oreilly.servlet.multipart;
006:
007: import java.io.IOException;
008:
009: import javax.servlet.ServletInputStream;
010:
011: /**
012: * A <code>LimitedServletInputStream</code> wraps another
013: * <code>ServletInputStream</code> in order to keep track of how many bytes
014: * have been read and detect when the Content-Length limit has been reached.
015: * This is necessary since some servlet containers are slow to notice the end
016: * of stream and cause the client code to hang if it tries to read past it.
017: *
018: * @author Jason Hunter
019: * @author Geoff Soutter
020: * @version 1.0, 2000/10/27, initial revision
021: */
022: public class LimitedServletInputStream extends ServletInputStream {
023:
024: /** input stream we are filtering */
025: private ServletInputStream in;
026:
027: /** number of bytes to read before giving up */
028: private int totalExpected;
029:
030: /** number of bytes we have currently read */
031: private int totalRead = 0;
032:
033: /**
034: * Creates a <code>LimitedServletInputStream</code> with the specified
035: * length limit that wraps the provided <code>ServletInputStream</code>.
036: */
037: public LimitedServletInputStream(ServletInputStream in,
038: int totalExpected) {
039: this .in = in;
040: this .totalExpected = totalExpected;
041: }
042:
043: /**
044: * Implement length limitation on top of the <code>readLine</code> method of
045: * the wrapped <code>ServletInputStream</code>.
046: *
047: * @param b an array of bytes into which data is read.
048: * @param off an integer specifying the character at which
049: * this method begins reading.
050: * @param len an integer specifying the maximum number of
051: * bytes to read.
052: * @return an integer specifying the actual number of bytes
053: * read, or -1 if the end of the stream is reached.
054: * @exception IOException if an I/O error occurs.
055: */
056: public int readLine(byte b[], int off, int len) throws IOException {
057: int result, left = totalExpected - totalRead;
058: if (left <= 0) {
059: return -1;
060: } else {
061: result = ((ServletInputStream) in).readLine(b, off, Math
062: .min(left, len));
063: }
064: if (result > 0) {
065: totalRead += result;
066: }
067: return result;
068: }
069:
070: /**
071: * Implement length limitation on top of the <code>read</code> method of
072: * the wrapped <code>ServletInputStream</code>.
073: *
074: * @return the next byte of data, or <code>-1</code> if the end of the
075: * stream is reached.
076: * @exception IOException if an I/O error occurs.
077: */
078: public int read() throws IOException {
079: if (totalRead >= totalExpected) {
080: return -1;
081: }
082:
083: int result = in.read();
084: if (result != -1) {
085: totalRead++;
086: }
087: return result;
088: }
089:
090: /**
091: * Implement length limitation on top of the <code>read</code> method of
092: * the wrapped <code>ServletInputStream</code>.
093: *
094: * @param b destination buffer.
095: * @param off offset at which to start storing bytes.
096: * @param len maximum number of bytes to read.
097: * @return the number of bytes read, or <code>-1</code> if the end of
098: * the stream has been reached.
099: * @exception IOException if an I/O error occurs.
100: */
101: public int read(byte b[], int off, int len) throws IOException {
102: int result, left = totalExpected - totalRead;
103: if (left <= 0) {
104: return -1;
105: } else {
106: result = in.read(b, off, Math.min(left, len));
107: }
108: if (result > 0) {
109: totalRead += result;
110: }
111: return result;
112: }
113: }
|