001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.fileupload.util;
018
019 import java.io.FilterInputStream;
020 import java.io.IOException;
021 import java.io.InputStream;
022
023
024 /**
025 * An input stream, which limits its data size. This stream is
026 * used, if the content length is unknown.
027 */
028 public abstract class LimitedInputStream
029 extends FilterInputStream implements Closeable {
030 /**
031 * The maximum size of an item, in bytes.
032 */
033 private long sizeMax;
034 /**
035 * The current number of bytes.
036 */
037 private long count;
038 /**
039 * Whether this stream is already closed.
040 */
041 private boolean closed;
042
043 /**
044 * Creates a new instance.
045 * @param pIn The input stream, which shall be limited.
046 * @param pSizeMax The limit; no more than this number of bytes
047 * shall be returned by the source stream.
048 */
049 public LimitedInputStream(InputStream pIn, long pSizeMax) {
050 super(pIn);
051 sizeMax = pSizeMax;
052 }
053
054 /**
055 * Called to indicate, that the input streams limit has
056 * been exceeded.
057 * @param pSizeMax The input streams limit, in bytes.
058 * @param pCount The actual number of bytes.
059 * @throws IOException The called method is expected
060 * to raise an IOException.
061 */
062 protected abstract void raiseError(long pSizeMax, long pCount)
063 throws IOException;
064
065 /** Called to check, whether the input streams
066 * limit is reached.
067 * @throws IOException The given limit is exceeded.
068 */
069 private void checkLimit() throws IOException {
070 if (count > sizeMax) {
071 raiseError(sizeMax, count);
072 }
073 }
074
075 /**
076 * Reads the next byte of data from this input stream. The value
077 * byte is returned as an <code>int</code> in the range
078 * <code>0</code> to <code>255</code>. If no byte is available
079 * because the end of the stream has been reached, the value
080 * <code>-1</code> is returned. This method blocks until input data
081 * is available, the end of the stream is detected, or an exception
082 * is thrown.
083 * <p>
084 * This method
085 * simply performs <code>in.read()</code> and returns the result.
086 *
087 * @return the next byte of data, or <code>-1</code> if the end of the
088 * stream is reached.
089 * @exception IOException if an I/O error occurs.
090 * @see java.io.FilterInputStream#in
091 */
092 public int read() throws IOException {
093 int res = super.read();
094 if (res != -1) {
095 count++;
096 checkLimit();
097 }
098 return res;
099 }
100
101 /**
102 * Reads up to <code>len</code> bytes of data from this input stream
103 * into an array of bytes. If <code>len</code> is not zero, the method
104 * blocks until some input is available; otherwise, no
105 * bytes are read and <code>0</code> is returned.
106 * <p>
107 * This method simply performs <code>in.read(b, off, len)</code>
108 * and returns the result.
109 *
110 * @param b the buffer into which the data is read.
111 * @param off The start offset in the destination array
112 * <code>b</code>.
113 * @param len the maximum number of bytes read.
114 * @return the total number of bytes read into the buffer, or
115 * <code>-1</code> if there is no more data because the end of
116 * the stream has been reached.
117 * @exception NullPointerException If <code>b</code> is <code>null</code>.
118 * @exception IndexOutOfBoundsException If <code>off</code> is negative,
119 * <code>len</code> is negative, or <code>len</code> is greater than
120 * <code>b.length - off</code>
121 * @exception IOException if an I/O error occurs.
122 * @see java.io.FilterInputStream#in
123 */
124 public int read(byte[] b, int off, int len) throws IOException {
125 int res = super.read(b, off, len);
126 if (res > 0) {
127 count += res;
128 checkLimit();
129 }
130 return res;
131 }
132
133 /**
134 * Returns, whether this stream is already closed.
135 * @return True, if the stream is closed, otherwise false.
136 * @throws IOException An I/O error occurred.
137 */
138 public boolean isClosed() throws IOException {
139 return closed;
140 }
141
142 /**
143 * Closes this input stream and releases any system resources
144 * associated with the stream.
145 * This
146 * method simply performs <code>in.close()</code>.
147 *
148 * @exception IOException if an I/O error occurs.
149 * @see java.io.FilterInputStream#in
150 */
151 public void close() throws IOException {
152 closed = true;
153 super.close();
154 }
155 }