Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

InputStream.read(byte[], 0 length) stops early?

I have been writing something to read a request stream (containing gzipped data) from an incoming HttpServletRequest ('request' below), however it appears that the normal InputStream read method doesn't actually read all content?

My code was:

InputStream requestStream = request.getInputStream();
if ((length = request.getContentLength()) != -1)
{
    received = new byte[length];
    requestStream.read(received, 0, length);
}
else
{
    // create a variable length list of bytes
    List<Byte> bytes = new ArrayList<Byte>();

    boolean endLoop = false;
    while (!endLoop)
    {
        // try and read the next value from the stream.. if not -1, add it to the list as a byte. if
        // it is, we've reached the end.
        int currentByte = requestStream.read();
        if (currentByte != -1)
            bytes.add((byte) currentByte);
        else
            endLoop = true;
    }
    // initialize the final byte[] to the right length and add each byte into it in the right order.
    received = new byte[bytes.size()];
    for (int i = 0; i < bytes.size(); i++)
    {
        received[i] = bytes.get(i);
    }
}

What I found during testing was that sometimes the top part (for when a content length is present) would just stop reading part way through the incoming request stream and leave the remainder of the 'received' byte array blank. If I just make it run the else part of the if statement at all times, it reads fine and all the expected bytes are placed in 'received'.

So, it seems like I can just leave my code alone now with that change, but does anyone have any idea why the normal 'read'(byte[], int, int)' method stopped reading? The description says that it may stop if an end of file is present. Could it be that the gzipped data just happened to include bytes matching whatever the signature for that looks like?

like image 963
user unknown Avatar asked Aug 13 '12 15:08

user unknown


2 Answers

You need to add a while loop at the top to get all the bytes. The stream will attempt to read as many bytes as it can, but it is not required to return len bytes at once:

An attempt is made to read as many as len bytes, but a smaller number may be read, possibly zero.

if ((length = request.getContentLength()) != -1)
{
    received = new byte[length];
    int pos = 0;
    do {
        int read = requestStream.read(received, pos, length-pos);

        // check for end of file or error
        if (read == -1) {
            break;
        } else {
            pos += read;
        }
    } while (pos < length);
}

EDIT: fixed while.

like image 93
Sergey Kalinichenko Avatar answered Oct 07 '22 12:10

Sergey Kalinichenko


You need to see how much of the buffer was filled. Its only guaranteed to give you at at least one byte.

Perhaps what you wanted was DataInputStream.readFully();

like image 39
Peter Lawrey Avatar answered Oct 07 '22 14:10

Peter Lawrey