FileDocCategorySizeDatePackage
ChunkedInputStream.javaAPI DocAndroid 1.5 API9859Wed May 06 22:41:10 BST 2009org.apache.http.impl.io

ChunkedInputStream

public class ChunkedInputStream extends InputStream
Implements chunked transfer coding. See RFC 2616, section 3.6.1. It transparently coalesces chunks of a HTTP stream that uses chunked transfer coding. After the stream is read to the end, it provides access to the trailers, if any.

Note that this class NEVER closes the underlying stream, even when close gets called. Instead, it will read until the "end" of its chunking on close, which allows for the seamless execution of subsequent HTTP 1.1 requests, while not requiring the client to remember to read the entire contents of the response.

author
Ortwin Glueck
author
Sean C. Sullivan
author
Martin Elwin
author
Eric Johnson
author
Mike Bowler
author
Michael Becke
author
Oleg Kalnichevski
since
4.0

Fields Summary
private SessionInputBuffer
in
The session input buffer
private final CharArrayBuffer
buffer
private int
chunkSize
The chunk size
private int
pos
The current position within the current chunk
private boolean
bof
True if we'are at the beginning of stream
private boolean
eof
True if we've reached the end of stream
private boolean
closed
True if this stream is closed
private Header[]
footers
Constructors Summary
public ChunkedInputStream(SessionInputBuffer in)


        
        super();
        if (in == null) {
            throw new IllegalArgumentException("Session input buffer may not be null");
        }
        this.in = in;
        this.pos = 0;
        this.buffer = new CharArrayBuffer(16);
    
Methods Summary
public voidclose()
Upon close, this reads the remainder of the chunked message, leaving the underlying socket at a position to start reading the next response without scanning.

throws
IOException If an IO problem occurs.

        if (!closed) {
            try {
                if (!eof) {
                    exhaustInputStream(this);
                }
            } finally {
                eof = true;
                closed = true;
            }
        }
    
static voidexhaustInputStream(java.io.InputStream inStream)
Exhaust an input stream, reading until EOF has been encountered.

Note that this function is intended as a non-public utility. This is a little weird, but it seemed silly to make a utility class for this one function, so instead it is just static and shared that way.

param
inStream The {@link InputStream} to exhaust.
throws
IOException If an IO problem occurs

        // read and discard the remainder of the message
        byte buffer[] = new byte[1024];
        while (inStream.read(buffer) >= 0) {
            ;
        }
    
private intgetChunkSize()
Expects the stream to start with a chunksize in hex with optional comments after a semicolon. The line must end with a CRLF: "a3; some comment\r\n" Positions the stream at the start of the next line.

param
in The new input stream.
param
required true if a valid chunk must be present, false otherwise.
return
the chunk size as integer
throws
IOException when the chunk size could not be parsed

        // skip CRLF
        if (!bof) {
            int cr = in.read();
            int lf = in.read();
            if ((cr != HTTP.CR) || (lf != HTTP.LF)) { 
                throw new MalformedChunkCodingException(
                    "CRLF expected at end of chunk");
            }
        }
        //parse data
        this.buffer.clear();
        int i = this.in.readLine(this.buffer);
        if (i == -1) {
            throw new MalformedChunkCodingException(
                    "Chunked stream ended unexpectedly");
        }
        int separator = this.buffer.indexOf(';");
        if (separator < 0) {
            separator = this.buffer.length();
        }
        try {
            return Integer.parseInt(this.buffer.substringTrimmed(0, separator), 16);
        } catch (NumberFormatException e) {
            throw new MalformedChunkCodingException("Bad chunk header");
        }
    
public org.apache.http.Header[]getFooters()

        return (Header[])this.footers.clone();
    
private voidnextChunk()
Read the next chunk.

throws
IOException If an IO error occurs.

        chunkSize = getChunkSize();
        if (chunkSize < 0) {
            throw new MalformedChunkCodingException("Negative chunk size");
        }
        bof = false;
        pos = 0;
        if (chunkSize == 0) {
            eof = true;
            parseTrailerHeaders();
        }
    
private voidparseTrailerHeaders()
Reads and stores the Trailer headers.

throws
IOException If an IO problem occurs

        try {
            this.footers = AbstractMessageParser.parseHeaders
                (in, -1, -1, null);
        } catch (HttpException e) {
            IOException ioe = new MalformedChunkCodingException("Invalid footer: " 
                    + e.getMessage());
            ExceptionUtils.initCause(ioe, e); 
            throw ioe;
        }
    
public intread()

Returns all the data in a chunked stream in coalesced form. A chunk is followed by a CRLF. The method returns -1 as soon as a chunksize of 0 is detected.

Trailer headers are read automcatically at the end of the stream and can be obtained with the getResponseFooters() method.

return
-1 of the end of the stream has been reached or the next data byte
throws
IOException If an IO problem occurs

        if (this.closed) {
            throw new IOException("Attempted read from closed stream.");
        }
        if (this.eof) {
            return -1;
        } 
        if (this.pos >= this.chunkSize) {
            nextChunk();
            if (this.eof) { 
                return -1;
            }
        }
        pos++;
        return in.read();
    
public intread(byte[] b, int off, int len)
Read some bytes from the stream.

param
b The byte array that will hold the contents from the stream.
param
off The offset into the byte array at which bytes will start to be placed.
param
len the maximum number of bytes that can be returned.
return
The number of bytes returned or -1 if the end of stream has been reached.
see
java.io.InputStream#read(byte[], int, int)
throws
IOException if an IO problem occurs.


        if (closed) {
            throw new IOException("Attempted read from closed stream.");
        }

        if (eof) { 
            return -1;
        }
        if (pos >= chunkSize) {
            nextChunk();
            if (eof) { 
                return -1;
            }
        }
        len = Math.min(len, chunkSize - pos);
        int count = in.read(b, off, len);
        pos += count;
        return count;
    
public intread(byte[] b)
Read some bytes from the stream.

param
b The byte array that will hold the contents from the stream.
return
The number of bytes returned or -1 if the end of stream has been reached.
see
java.io.InputStream#read(byte[])
throws
IOException if an IO problem occurs.

        return read(b, 0, b.length);