org.openqa.jetty.http.HttpInputStream.java Source code

Java tutorial

Introduction

Here is the source code for org.openqa.jetty.http.HttpInputStream.java

Source

// ========================================================================
// $Id: HttpInputStream.java,v 1.13 2005/08/23 20:02:26 gregwilkins Exp $
// Copyright 1996-2004 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at 
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ========================================================================

package org.openqa.jetty.http;

import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;

import org.apache.commons.logging.Log;
import org.openqa.jetty.log.LogFactory;
import org.openqa.jetty.util.LineInput;
import org.openqa.jetty.util.StringUtil;

/* ------------------------------------------------------------ */
/** HTTP Chunking InputStream. 
 * This FilterInputStream acts as a BufferedInputStream until
 * setChunking(true) is called.  Once chunking is
 * enabled, the raw stream is chunk decoded as per RFC2616.
 *
 * The "8859-1" encoding is used on underlying LineInput instance for
 * line based reads from the raw stream.
 *
 * This class is not synchronized and should be synchronized
 * explicitly if an instance is used by multiple threads.
 *
 * @see org.openqa.jetty.util.LineInput
 * @version $Id: HttpInputStream.java,v 1.13 2005/08/23 20:02:26 gregwilkins Exp $
 * @author Greg Wilkins (gregw)
 */
public class HttpInputStream extends FilterInputStream {
    private static Log log = LogFactory.getLog(HttpInputStream.class);

    /* ------------------------------------------------------------ */
    private static ClosedStream __closedStream = new ClosedStream();

    /* ------------------------------------------------------------ */
    private ChunkingInputStream _deChunker;
    private LineInput _realIn;
    private boolean _chunking;
    private OutputStream _expectContinues;

    /* ------------------------------------------------------------ */
    /** Constructor.
     */
    public HttpInputStream(InputStream in) {
        this(in, 4096);
    }

    /* ------------------------------------------------------------ */
    /** Constructor.
     */
    public HttpInputStream(InputStream in, int bufferSize) {
        super(null);
        try {
            _realIn = new LineInput(in, bufferSize, StringUtil.__ISO_8859_1);
        } catch (UnsupportedEncodingException e) {
            log.fatal(e);
            System.exit(1);
        }
        this.in = _realIn;
    }

    /* ------------------------------------------------------------ */
    /**
     * @return OutputStream object set by setExpectContinues()
     * @see #expectContinues()
     */
    public OutputStream getExpectContinues() {
        return _expectContinues;
    }

    /* ------------------------------------------------------------ */
    /**
     * @param expectContinues The expectContinues to set.
     */
    public void setExpectContinues(OutputStream expectContinues) {
        _expectContinues = expectContinues;
    }

    /* ------------------------------------------------------------ */
    /* 
     * @see java.io.InputStream#read()
     */
    public int read() throws IOException {
        if (_expectContinues != null)
            expectContinues();
        return super.read();
    }

    /* ------------------------------------------------------------ */
    /* 
     * @see java.io.InputStream#read(byte[], int, int)
     */
    public int read(byte[] b, int off, int len) throws IOException {
        if (_expectContinues != null)
            expectContinues();
        return super.read(b, off, len);
    }

    /* ------------------------------------------------------------ */
    /* 
     * @see java.io.InputStream#read(byte[])
     */
    public int read(byte[] b) throws IOException {
        if (_expectContinues != null)
            expectContinues();
        return super.read(b);
    }

    /* ------------------------------------------------------------ */
    /* 
     * @see java.io.InputStream#skip(long)
     */
    public long skip(long n) throws IOException {
        if (_expectContinues != null)
            expectContinues();
        return super.skip(n);
    }

    /* ------------------------------------------------------------ */
    private void expectContinues() throws IOException {
        try {
            if (available() <= 0) {
                _expectContinues.write(HttpResponse.__Continue);
                _expectContinues.flush();
            }
        } finally {
            _expectContinues = null;
        }

    }

    /* ------------------------------------------------------------ */
    /** Get the raw stream.
     * A stream without filters or chunking is returned. This stream
     * may still be buffered and uprocessed bytes may be in the buffer.
     * @return Raw InputStream.
     */
    public InputStream getInputStream() {
        return _realIn;
    }

    /* ------------------------------------------------------------ */
    /** Get Filter InputStream.
     * Get the current top of the InputStream filter stack
     * @return InputStream.
     */
    public InputStream getFilterStream() {
        return in;
    }

    /* ------------------------------------------------------------ */
    /** Set Filter InputStream.
     * Set input filter stream, which should be constructed to wrap
     * the stream returned from get FilterStream.
     */
    public void setFilterStream(InputStream filter) {
        in = filter;
    }

    /* ------------------------------------------------------------ */
    /** Get chunking mode 
     */
    public boolean isChunking() {
        return _chunking;
    }

    /* ------------------------------------------------------------ */
    /** Set chunking mode.
     * Chunking can only be turned off with a call to resetStream().
     * @exception IllegalStateException Checking cannot be set if
     * a content length has been set.
     */
    public void setChunking() throws IllegalStateException {
        if (_realIn.getByteLimit() >= 0)
            throw new IllegalStateException("Has Content-Length");
        if (_deChunker == null)
            _deChunker = new ChunkingInputStream(_realIn);
        in = _deChunker;

        _chunking = true;
        _deChunker._trailer = null;
    }

    /* ------------------------------------------------------------ */
    /** Reset the stream.
     * Turn chunking off and disable all filters.
     * @exception IllegalStateException The stream cannot be reset if
     * there is some unread chunked input or a content length greater
     * than zero remaining.
     */
    public void resetStream() throws IllegalStateException {
        if ((_deChunker != null && _deChunker._chunkSize > 0) || _realIn.getByteLimit() > 0)
            throw new IllegalStateException("Unread input");
        if (log.isTraceEnabled())
            log.trace("resetStream()");
        in = _realIn;
        if (_deChunker != null)
            _deChunker.resetStream();
        _chunking = false;
        _realIn.setByteLimit(-1);
    }

    /* ------------------------------------------------------------ */
    public void close() throws IOException {
        in = __closedStream;
    }

    /* ------------------------------------------------------------ */
    /** Set the content length.
     * Only this number of bytes can be read before EOF is returned.
     * @param len length.
     */
    public void setContentLength(int len) {
        if (_chunking && len >= 0 && getExpectContinues() == null)
            throw new IllegalStateException("Chunking");
        _realIn.setByteLimit(len);
    }

    /* ------------------------------------------------------------ */
    void unsafeSetContentLength(int len) {
        _realIn.setByteLimit(len);
    }

    /* ------------------------------------------------------------ */
    /** Get the content length.
     * @return Number of bytes until EOF is returned or -1 for no limit.
     */
    public int getContentLength() {
        return _realIn.getByteLimit();
    }

    /* ------------------------------------------------------------ */
    public HttpFields getTrailer() {
        return _deChunker._trailer;
    }

    /* ------------------------------------------------------------ */
    public void destroy() {
        if (_realIn != null)
            _realIn.destroy();
        _realIn = null;
        _deChunker = null;
        _expectContinues = null;
    }

    /* ------------------------------------------------------------ */
    /** A closed input stream.
     */
    private static class ClosedStream extends InputStream {
        /* ------------------------------------------------------------ */
        public int read() throws IOException {
            return -1;
        }
    }
}