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 005package com.oreilly.servlet.multipart; 006 007import java.io.IOException; 008 009import 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 */ 022public 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, int totalExpected) { 038 this.in = in; 039 this.totalExpected = totalExpected; 040 } 041 042 /** 043 * Implement length limitation on top of the <code>readLine</code> method of 044 * the wrapped <code>ServletInputStream</code>. 045 * 046 * @param b an array of bytes into which data is read. 047 * @param off an integer specifying the character at which 048 * this method begins reading. 049 * @param len an integer specifying the maximum number of 050 * bytes to read. 051 * @return an integer specifying the actual number of bytes 052 * read, or -1 if the end of the stream is reached. 053 * @exception IOException if an I/O error occurs. 054 */ 055 public int readLine(byte b[], int off, int len) throws IOException { 056 int result, left = totalExpected - totalRead; 057 if (left <= 0) { 058 return -1; 059 } else { 060 result = ((ServletInputStream)in).readLine(b, off, Math.min(left, len)); 061 } 062 if (result > 0) { 063 totalRead += result; 064 } 065 return result; 066 } 067 068 /** 069 * Implement length limitation on top of the <code>read</code> method of 070 * the wrapped <code>ServletInputStream</code>. 071 * 072 * @return the next byte of data, or <code>-1</code> if the end of the 073 * stream is reached. 074 * @exception IOException if an I/O error occurs. 075 */ 076 public int read() throws IOException { 077 if (totalRead >= totalExpected) { 078 return -1; 079 } 080 081 int result = in.read(); 082 if (result != -1) { 083 totalRead++; 084 } 085 return result; 086 } 087 088 /** 089 * Implement length limitation on top of the <code>read</code> method of 090 * the wrapped <code>ServletInputStream</code>. 091 * 092 * @param b destination buffer. 093 * @param off offset at which to start storing bytes. 094 * @param len maximum number of bytes to read. 095 * @return the number of bytes read, or <code>-1</code> if the end of 096 * the stream has been reached. 097 * @exception IOException if an I/O error occurs. 098 */ 099 public int read( byte b[], int off, int len ) throws IOException { 100 int result, left = totalExpected - totalRead; 101 if (left <= 0) { 102 return -1; 103 } else { 104 result = in.read(b, off, Math.min(left, len)); 105 } 106 if (result > 0) { 107 totalRead += result; 108 } 109 return result; 110 } 111}