All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.oreilly.servlet.multipart.BufferedServletInputStream Maven / Gradle / Ivy

The newest version!
// Copyright (C) 1999-2001 by Jason Hunter .
// All rights reserved.  Use of this class is limited.
// Please see the LICENSE for more information.
 
package com.oreilly.servlet.multipart;

import jakarta.servlet.ReadListener;
import jakarta.servlet.ServletInputStream;

import java.io.IOException;

/**
 * A BufferedServletInputStream wraps a
 * ServletInputStream in order to provide input buffering and to
 * avoid calling the the readLine method of the wrapped
 * ServletInputStream.
 * <p>
 * This is necessary because some servlet containers rely on the default 
 * implementation of the readLine method provided by the Servlet
 * API classes, which is very slow. Tomcat 3.2, Tomcat 3.1, the JSWDK 1.0 web 
 * server and the JSDK2.1 web server are all known to need this class for 
 * performance reasons. 
 * <p>
 * Also, it may be used to work around a bug in the Servlet API 2.0 
 * implementation of readLine which contains a bug that causes
 * ArrayIndexOutOfBoundsExceptions under certain conditions.
 * Apache JServ is known to suffer from this bug.
 * 
 * @author Geoff Soutter
 * @version 1.1, 2001/05/21, removed block of commented out code
 * @version 1.0, 2000/10/27, initial revision
 */
public class BufferedServletInputStream extends ServletInputStream {
  
  /** input stream we are filtering */
  private ServletInputStream in;
  
  /** our buffer */
  private byte[] buf = new byte[64*1024];  // 64k
  
  /** number of bytes we've read into the buffer */
  private int count; 
  
  /** current position in the buffer */
  private int pos;
  
  /**
   * Creates a BufferedServletInputStream that wraps the provided
   * ServletInputStream.
   * 
   * @param in  a servlet input stream.
   */
  public BufferedServletInputStream(ServletInputStream in) {
    this.in = in;
  }

  /**
   * Fill up our buffer from the underlying input stream. Users of this
   * method must ensure that they use all characters in the buffer before
   * calling this method.
   * 
   * @exception  IOException  if an I/O error occurs.
   */
  private void fill() throws IOException {
    int i = in.read(buf, 0, buf.length);
    if (i > 0) {
      pos = 0;
      count = i;
    }
  }
    
  /**
   * Implement buffering on top of the readLine method of
   * the wrapped ServletInputStream.
   *
   * @param b    an array of bytes into which data is read.
   * @param off  an integer specifying the character at which
   *        this method begins reading.
   * @param len  an integer specifying the maximum number of 
   *        bytes to read.
   * @return     an integer specifying the actual number of bytes 
   *        read, or -1 if the end of the stream is reached.
   * @exception  IOException  if an I/O error occurs.
   */
  public int readLine(byte b[], int off, int len) throws IOException {
    int total = 0;
    if (len == 0) {
      return 0;
    }
    
    int avail = count - pos;
    if (avail <= 0) {
      fill();
      avail = count - pos;
      if (avail <= 0) {
        return -1;
      }
    }
    int copy = Math.min(len, avail);
    int eol = findeol(buf, pos, copy);
    if (eol != -1) {
      copy = eol;
    }
    System.arraycopy(buf, pos, b, off, copy);
    pos += copy;
    total += copy;
    
    while (total < len && eol == -1) {
      fill();
      avail = count - pos;
      if(avail <= 0) {
        return total;
      }
      copy = Math.min(len - total, avail);
      eol = findeol(buf, pos, copy);
      if (eol != -1) {
        copy = eol;
      }
      System.arraycopy(buf, pos, b, off + total, copy);
      pos += copy;
      total += copy;
    }
    return total;
  }

  /**
   * Attempt to find the '\n' end of line marker as defined in the comment of
   * the readLine method of ServletInputStream.
   * 
   * @param b byte array to search.
   * @param pos position in byte array to search from.
   * @param len maximum number of bytes to search.
   * 
   * @return the number of bytes including the \n, or -1 if none found.
   */
  private static int findeol(byte b[], int pos, int len) {
    int end = pos + len;
    int i = pos;
    while (i < end) {
      if (b[i++] == '\n') {
        return i - pos;
      }
    }
    return -1;
  }
  
  /**
   * Implement buffering on top of the read method of
   * the wrapped ServletInputStream.
   *
   * @return     the next byte of data, or -1 if the end of the
   *             stream is reached.
   * @exception  IOException  if an I/O error occurs.
   */
  public int read() throws IOException {
    if (count <= pos) {
      fill();
      if (count <= pos) {
        return -1;
      }
    }
    return buf[pos++] & 0xff;
  }

  /**
   * Implement buffering on top of the read method of
   * the wrapped ServletInputStream.
   *
   * @param      b     the buffer into which the data is read.
   * @param      off   the start offset of the data.
   * @param      len   the maximum number of bytes read.
   * @return     the total number of bytes read into the buffer, or
   *             -1 if there is no more data because the end
   *             of the stream has been reached.
   * @exception  IOException  if an I/O error occurs.
   */
  public int read(byte b[], int off, int len) throws IOException
  {
    int total = 0;
    while (total < len) {
      int avail = count - pos;
      if (avail <= 0) {
        fill();
        avail = count - pos;
        if(avail <= 0) {
          if (total > 0)
            return total;
          else
            return -1;
        }
      }
      int copy = Math.min(len - total, avail);
      System.arraycopy(buf, pos, b, off + total, copy);
      pos += copy;
      total += copy;
    }
    return total;
  }

  @Override
  public boolean isFinished() {
    return in.isFinished();
  }

  @Override
  public boolean isReady() {
    return in.isReady();
  }

  @Override
  public void setReadListener(ReadListener readListener) {
    in.setReadListener(readListener);
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy