blob: 37c326f2d4a9231943e3e431bf738ba9daef5077 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 1999, 2005 IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.equinox.http.servlet;
import java.io.IOException;
import java.io.InputStream;
import javax.servlet.ServletInputStream;
/**
* An input stream for reading servlet requests, it provides an
* efficient readLine method. This is an abstract class, to be
* implemented by a network services writer. For some application
* protocols, such as the HTTP POST and PUT methods, servlet writers
* use the input stream to get data from clients. They access the
* input stream via the ServletRequest's getInputStream method,
* available from within the servlet's service method. Subclasses of
* ServletInputStream must provide an implementation of the read()
* method.
*
* <p>
* This InputStream Object just forwards all requests to the real InputStream object
* It is intended that that would be the real Sock InputStream. This has some
* problems if we ever need to restart the stream with another Servlet/etc, so this
* may need to change some day change.
*/
public class ServletInputStreamImpl extends ServletInputStream {
private InputStream in;
private ServletInputStream servletInputStream = null;
protected ServletInputStreamImpl(InputStream in) {
super();
this.in = in;
}
private void checkOpen() throws IOException {
if (in == null) {
throw new IOException("ServletInputStream closed"); //$NON-NLS-1$
}
}
/**
* Returns the number of bytes that can be read from this input
* stream without blocking. The available method of
* <code>InputStream</code> returns <code>0</code>. This method
* <B>should</B> be overridden by subclasses.
*
* @return the number of bytes that can be read from this input stream
* without blocking.
* @exception IOException if an I/O error occurs.
* @since JDK1.0
*/
public int available() throws IOException {
checkOpen();
return in.available();
}
/**
* Closes this input stream and releases any system resources
* associated with the stream.
* <p>
* The <code>close</code> method of <code>InputStream</code> does nothing.
*
* @exception IOException if an I/O error occurs.
* @since JDK1.0
*/
public void close() throws IOException {
in = null;
}
/**
* Return the ServletInputStream to use for reading data after the
* HTTP headers have been read. If a Content-Length header is available
*
* @param len Content-Length of InputStream
* @return InputStream for use by servlets
* @exception
*/
ServletInputStream getServletInputStream(int len) {
if (servletInputStream == null) {
synchronized (this) {
if (servletInputStream == null) {
if (len > 0) {
servletInputStream = new ContentLength(this, len);
} else {
servletInputStream = this;
}
}
}
}
return servletInputStream;
}
/**
* Marks the current position in this input stream. A subsequent
* call to the <code>reset</code> method repositions this stream at
* the last marked position so that subsequent reads re-read the same
* bytes.
* <p>
* The <code>readlimit</code> arguments tells this input stream to
* allow that many bytes to be read before the mark position gets
* invalidated.
* <p>
* The <code>mark</code> method of <code>InputStream</code> does nothing.
*
* @param readlimit the maximum limit of bytes that can be read before
* the mark position becomes invalid.
* @see java.io.InputStream#reset()
* @since JDK1.0
*/
public void mark(int readLimit) {
in.mark(readLimit);
}
/**
* Tests if this input stream supports the <code>mark</code>
* and <code>reset</code> methods. The <code>markSupported</code>
* method of <code>InputStream</code> returns <code>false</code>.
*
* @return <code>true</code> if this true type supports the mark and reset
* method; <code>false</code> otherwise.
* @see java.io.InputStream#mark(int)
* @see java.io.InputStream#reset()
* @since JDK1.0
*/
public boolean markSupported() {
return in.markSupported();
}
/**
* Reads the next byte of data from this input stream. The value
* byte is returned as an <code>int</code> in the range
* <code>0</code> to <code>255</code>. If no byte is available
* because the end of the stream has been reached, the value
* <code>-1</code> is returned. This method blocks until input data
* is available, the end of the stream is detected, or an exception
* is thrown.
* <p>
* A subclass must provide an implementation of this method.
*
* @return the next byte of data, or <code>-1</code> if the end of the
* stream is reached.
* @exception IOException if an I/O error occurs.
* @since JDK1.0
*/
public int read() throws IOException {
checkOpen();
return in.read();
}
/**
* Reads up to <code>b.length</code> bytes of data from this input
* stream into an array of bytes.
* <p>
* The <code>read</code> method of <code>InputStream</code> calls
* the <code>read</code> method of three arguments with the arguments
* <code>b</code>, <code>0</code>, and <code>b.length</code>.
*
* @param b the buffer into which the data is read.
* @return the total number of bytes read into the buffer, or
* <code>-1</code> is there is no more data because the end of
* the stream has been reached.
* @exception IOException if an I/O error occurs.
* @see java.io.InputStream#read(byte[], int, int)
* @since JDK1.0
*/
public int read(byte[] b) throws IOException {
checkOpen();
return in.read(b, 0, b.length);
}
/**
* Reads up to <code>len</code> bytes of data from this input stream
* into an array of bytes. This method blocks until some input is
* available. If the argument <code>b</code> is <code>null</code>, a
* <code>NullPointerException</code> is thrown.
* <p>
* The <code>read</code> method of <code>InputStream</code> reads a
* single byte at a time using the read method of zero arguments to
* fill in the array. Subclasses are encouraged to provide a more
* efficient implementation of this method.
*
* @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
* <code>-1</code> if there is no more data because the end of
* the stream has been reached.
* @exception IOException if an I/O error occurs.
* @see java.io.InputStream#read()
* @since JDK1.0
*/
public int read(byte[] b, int off, int len) throws IOException {
checkOpen();
return in.read(b, off, len);
}
/**
* Repositions this stream to the position at the time the
* <code>mark</code> method was last called on this input stream.
* <p>
* The <code>reset</code> method of <code>InputStream</code> throws
* an <code>IOException</code>, because input streams, by default, do
* not support <code>mark</code> and <code>reset</code>.
* <p>
* Stream marks are intended to be used in
* situations where you need to read ahead a little to see what's in
* the stream. Often this is most easily done by invoking some
* general parser. If the stream is of the type handled by the
* parser, it just chugs along happily. If the stream is not of
* that type, the parser should toss an exception when it fails,
* which, if it happens within readlimit bytes, allows the outer
* code to reset the stream and try another parser.
*
* @exception IOException if this stream has not been marked or if the
* mark has been invalidated.
* @see java.io.InputStream#mark(int)
* @see java.io.IOException
* @since JDK1.0
*/
public void reset() throws IOException {
checkOpen();
in.reset();
}
/**
* Skips over and discards <code>n</code> bytes of data from this
* input stream. The <code>skip</code> method may, for a variety of
* reasons, end up skipping over some smaller number of bytes,
* possibly <code>0</code>. The actual number of bytes skipped is
* returned.
* <p>
* The <code>skip</code> method of <code>InputStream</code> creates
* a byte array of length <code>n</code> and then reads into it until
* <code>n</code> bytes have been read or the end of the stream has
* been reached. Subclasses are encouraged to provide a more
* efficient implementation of this method.
*
* @param n the number of bytes to be skipped.
* @return the actual number of bytes skipped.
* @exception IOException if an I/O error occurs.
* @since JDK1.0
*/
public long skip(long len) throws IOException {
checkOpen();
return in.skip(len);
}
/**
* ServletInputStream which limit readable data to the specified content length.
* After the number of bytes have been read, EOF(-1) is returned from the read
* method.
*
*/
static class ContentLength extends ServletInputStream {
private int contentLength;
private int mark;
private ServletInputStream in;
ContentLength(ServletInputStream in, int len) {
super();
this.in = in;
contentLength = len;
mark = len;
}
/**
* Returns the number of bytes that can be read from this input
* stream without blocking. The available method of
* <code>InputStream</code> returns <code>0</code>. This method
* <B>should</B> be overridden by subclasses.
*
* @return the number of bytes that can be read from this input stream
* without blocking.
* @exception IOException if an I/O error occurs.
* @since JDK1.0
*/
public int available() throws IOException {
int avail = in.available();
if (contentLength < avail) {
return contentLength;
}
return avail;
}
/**
* Closes this input stream and releases any system resources
* associated with the stream.
* <p>
* The <code>close</code> method of <code>InputStream</code> does nothing.
*
* @exception IOException if an I/O error occurs.
* @since JDK1.0
*/
public void close() throws IOException {
in.close();
}
/**
* Marks the current position in this input stream. A subsequent
* call to the <code>reset</code> method repositions this stream at
* the last marked position so that subsequent reads re-read the same
* bytes.
* <p>
* The <code>readlimit</code> arguments tells this input stream to
* allow that many bytes to be read before the mark position gets
* invalidated.
* <p>
* The <code>mark</code> method of <code>InputStream</code> does nothing.
*
* @param readlimit the maximum limit of bytes that can be read before
* the mark position becomes invalid.
* @see java.io.InputStream#reset()
* @since JDK1.0
*/
public void mark(int readLimit) {
in.mark(readLimit);
mark = contentLength;
}
/**
* Tests if this input stream supports the <code>mark</code>
* and <code>reset</code> methods. The <code>markSupported</code>
* method of <code>InputStream</code> returns <code>false</code>.
*
* @return <code>true</code> if this true type supports the mark and reset
* method; <code>false</code> otherwise.
* @see java.io.InputStream#mark(int)
* @see java.io.InputStream#reset()
* @since JDK1.0
*/
public boolean markSupported() {
return in.markSupported();
}
/**
* Reads the next byte of data from this input stream. The value
* byte is returned as an <code>int</code> in the range
* <code>0</code> to <code>255</code>. If no byte is available
* because the end of the stream has been reached, the value
* <code>-1</code> is returned. This method blocks until input data
* is available, the end of the stream is detected, or an exception
* is thrown.
* <p>
* A subclass must provide an implementation of this method.
*
* @return the next byte of data, or <code>-1</code> if the end of the
* stream is reached.
* @exception IOException if an I/O error occurs.
* @since JDK1.0
*/
public int read() throws IOException {
if (contentLength <= 0) {
return -1;
}
int read = in.read();
contentLength--;
return read;
}
/**
* Reads up to <code>b.length</code> bytes of data from this input
* stream into an array of bytes.
* <p>
* The <code>read</code> method of <code>InputStream</code> calls
* the <code>read</code> method of three arguments with the arguments
* <code>b</code>, <code>0</code>, and <code>b.length</code>.
*
* @param b the buffer into which the data is read.
* @return the total number of bytes read into the buffer, or
* <code>-1</code> is there is no more data because the end of
* the stream has been reached.
* @exception IOException if an I/O error occurs.
* @see java.io.InputStream#read(byte[], int, int)
* @since JDK1.0
*/
public int read(byte[] b) throws IOException {
if (contentLength <= 0) {
return -1;
}
int len = b.length;
if (contentLength < len) {
len = contentLength;
}
int read = in.read(b, 0, len);
contentLength -= read;
return read;
}
/**
* Reads up to <code>len</code> bytes of data from this input stream
* into an array of bytes. This method blocks until some input is
* available. If the argument <code>b</code> is <code>null</code>, a
* <code>NullPointerException</code> is thrown.
* <p>
* The <code>read</code> method of <code>InputStream</code> reads a
* single byte at a time using the read method of zero arguments to
* fill in the array. Subclasses are encouraged to provide a more
* efficient implementation of this method.
*
* @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
* <code>-1</code> if there is no more data because the end of
* the stream has been reached.
* @exception IOException if an I/O error occurs.
* @see java.io.InputStream#read()
* @since JDK1.0
*/
public int read(byte[] b, int off, int len) throws IOException {
if (contentLength <= 0) {
return -1;
}
if (contentLength < len) {
len = contentLength;
}
int read = in.read(b, off, len);
contentLength -= read;
return read;
}
/**
* Repositions this stream to the position at the time the
* <code>mark</code> method was last called on this input stream.
* <p>
* The <code>reset</code> method of <code>InputStream</code> throws
* an <code>IOException</code>, because input streams, by default, do
* not support <code>mark</code> and <code>reset</code>.
* <p>
* Stream marks are intended to be used in
* situations where you need to read ahead a little to see what's in
* the stream. Often this is most easily done by invoking some
* general parser. If the stream is of the type handled by the
* parser, it just chugs along happily. If the stream is not of
* that type, the parser should toss an exception when it fails,
* which, if it happens within readlimit bytes, allows the outer
* code to reset the stream and try another parser.
*
* @exception IOException if this stream has not been marked or if the
* mark has been invalidated.
* @see java.io.InputStream#mark(int)
* @see java.io.IOException
* @since JDK1.0
*/
public void reset() throws IOException {
in.reset();
contentLength = mark;
}
/**
* Skips over and discards <code>n</code> bytes of data from this
* input stream. The <code>skip</code> method may, for a variety of
* reasons, end up skipping over some smaller number of bytes,
* possibly <code>0</code>. The actual number of bytes skipped is
* returned.
* <p>
* The <code>skip</code> method of <code>InputStream</code> creates
* a byte array of length <code>n</code> and then reads into it until
* <code>n</code> bytes have been read or the end of the stream has
* been reached. Subclasses are encouraged to provide a more
* efficient implementation of this method.
*
* @param n the number of bytes to be skipped.
* @return the actual number of bytes skipped.
* @exception IOException if an I/O error occurs.
* @since JDK1.0
*/
public long skip(long len) throws IOException {
if (contentLength <= 0) {
return 0;
}
if (contentLength < len) {
len = contentLength;
}
long skipped = in.skip(len);
contentLength -= skipped;
return skipped;
}
}
}