1 /* LimitedLengthInputStream.java -- 2 Copyright (C) 2005, 2008 Free Software Foundation, Inc. 3 4 This file is part of GNU Classpath. 5 6 GNU Classpath is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 GNU Classpath is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GNU Classpath; see the file COPYING. If not, write to the 18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19 02110-1301 USA. 20 21 Linking this library statically or dynamically with other modules is 22 making a combined work based on this library. Thus, the terms and 23 conditions of the GNU General Public License cover the whole 24 combination. 25 26 As a special exception, the copyright holders of this library give you 27 permission to link this library with independent modules to produce an 28 executable, regardless of the license terms of these independent 29 modules, and to copy and distribute the resulting executable under 30 terms of your choice, provided that you also meet, for each linked 31 independent module, the terms and conditions of the license of that 32 module. An independent module is a module which is not derived from 33 or based on this library. If you modify this library, you may extend 34 this exception to your version of the library, but you are not 35 obligated to do so. If you do not wish to do so, delete this 36 exception statement from your version. */ 37 38 39 package gnu.java.net.protocol.http; 40 41 import java.io.IOException; 42 import java.io.InputStream; 43 44 /** 45 * InputStream that limits the total number of bytes that can be read 46 * from an underlying stream. In addition to limiting the number of 47 * bytes read, close() is not propagated to the underlying stream. 48 * 49 * @author David Daney (ddaney@avtrex.com) 50 */ 51 class LimitedLengthInputStream 52 extends InputStream 53 { 54 private long remainingLen; 55 private boolean restrictLen; 56 private HTTPConnection connection; 57 private boolean eof; 58 private InputStream in; 59 private boolean doClose; 60 handleClose()61 private void handleClose() 62 throws IOException 63 { 64 eof = true; 65 66 if (doClose) 67 in.close(); 68 else 69 connection.release(); 70 71 in = null; 72 connection = null; 73 } 74 75 /** 76 * Constructor. 77 * 78 * @param in the underlying stream 79 * 80 * @param maxLen the maximum number of bytes to read 81 * 82 * @param restrictLen if true the number of bytes that can be read 83 * from this stream will be limited to maxLen, otherwise the number 84 * of bytes is not restricted. 85 * 86 * @param con the HTTPConnection associated with this stream 87 * 88 * @param doClose if true con will be closed when finished reading, 89 * else it will be placed back in the connection pool. 90 * 91 */ LimitedLengthInputStream(InputStream in, long maxLen, boolean restrictLen, HTTPConnection con, boolean doClose)92 LimitedLengthInputStream(InputStream in, 93 long maxLen, 94 boolean restrictLen, 95 HTTPConnection con, 96 boolean doClose) 97 throws IOException 98 { 99 this.in = in; 100 this.remainingLen = maxLen; 101 this.restrictLen = restrictLen; 102 this.connection = con; 103 this.doClose = doClose; 104 105 if (restrictLen) 106 { 107 if (maxLen < 0) 108 throw new IllegalArgumentException(); 109 else if (maxLen == 0) 110 handleClose(); // Nothing to do, release the connection. 111 } 112 } 113 read()114 public synchronized int read() 115 throws IOException 116 { 117 if (eof) 118 return -1; // EOF 119 120 int r; 121 122 if (restrictLen) 123 { 124 r = in.read(); 125 if (-1 != r) 126 remainingLen--; 127 128 if (0 == remainingLen) 129 handleClose(); 130 } 131 else 132 { 133 r = in.read(); 134 if (r == -1) 135 handleClose(); 136 } 137 138 return r; 139 } 140 read(byte[] buffer)141 public int read(byte[] buffer) 142 throws IOException 143 { 144 return read(buffer, 0, buffer.length); 145 } 146 read(byte[] buffer, int offset, int length)147 public synchronized int read(byte[] buffer, int offset, int length) 148 throws IOException 149 { 150 if (eof) 151 return -1; // EOF 152 153 if (restrictLen && length > remainingLen) 154 length = (int) remainingLen; 155 156 int r = in.read(buffer, offset, length); 157 158 if (-1 == r) 159 handleClose(); 160 161 if (restrictLen && r > 0) 162 { 163 remainingLen -= r; 164 if (0 == remainingLen) 165 handleClose(); 166 } 167 return r; 168 } 169 skip(long n)170 public synchronized long skip(long n) 171 throws IOException 172 { 173 174 if (eof) 175 return 0; 176 177 if (restrictLen && n > remainingLen) 178 n = remainingLen; 179 180 long r = in.skip(n); 181 182 if (restrictLen) 183 { 184 remainingLen -= r; 185 if (0 == remainingLen) 186 handleClose(); 187 } 188 return r; 189 } 190 available()191 public synchronized int available() 192 throws IOException 193 { 194 if (eof) 195 return 0; 196 197 int a = in.available(); 198 if (restrictLen && a > remainingLen) 199 a = (int)remainingLen; 200 return a; 201 } 202 close()203 public synchronized void close() 204 throws IOException 205 { 206 if (eof) 207 return; 208 209 // If we get to here, the stream was not fully read. Just throw 210 // it away. 211 212 doClose = true; 213 214 handleClose(); 215 } 216 } 217