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

com.amazonaws.util.LengthCheckInputStream Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2014-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *  http://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file 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 com.amazonaws.util;

import java.io.IOException;
import java.io.InputStream;

import org.apache.http.annotation.NotThreadSafe;

import com.amazonaws.AmazonClientException;
import com.amazonaws.internal.SdkFilterInputStream;

/**
 * Used to perform length check to ensure the number of bytes read from the
 * underlying input stream is the same as the expected total.
 */
@NotThreadSafe
public class LengthCheckInputStream extends SdkFilterInputStream {
    public static final boolean INCLUDE_SKIPPED_BYTES = true;
    public static final boolean EXCLUDE_SKIPPED_BYTES = false;
    /**
     * Total number of bytes expected to be read from the underlying input
     * stream.
     */
    private final long expectedLength;
    /**
     * True if skipped bytes are to be included as part of the data length;
     * false otherwise.
     */
    private final boolean includeSkipped;
    /**
     * The length of the data read from the underlying input stream so far.
     */
    private long dataLength;
    private long marked; // used for mark-and-reset purposes

    /**
     * Constructs an input stream that performs length check to ensure the
     * number of bytes read from the underlying input stream is the same as the
     * expected total.
     * 
     * @param in
     *            the underlying input stream
     * @param expectedLength
     *            the total length of the data in bytes expected to be read from
     *            the underlying input stream; must be non-negative.
     * @param includeSkipped
     *            true if bytes skipped are to be considered as part of the data
     *            length; false otherwise. Typically, this parameter should be
     *            set to false for uploading data to AWS, but set to true for
     *            receiving data from AWS.
     */
    public LengthCheckInputStream(InputStream in, long expectedLength,
            boolean includeSkipped) {
        super(in);
        if (expectedLength < 0)
            throw new IllegalArgumentException();
        this.expectedLength = expectedLength;
        this.includeSkipped = includeSkipped;
    }

    /**
     * {@inheritDoc}
     * 
     * @throws AmazonClientException
     *             if the data length read has exceeded the expected total, or
     *             if the total data length is not the same as the expected
     *             total.
     */
    @Override
    public int read() throws IOException {
        final int c = super.read();
        if (c >= 0)
            dataLength++;
        checkLength(c == -1);
        return c;
    }

    /**
     * {@inheritDoc}
     * 
     * @throws AmazonClientException
     *             if the data length read has exceeded the expected total, or
     *             if the total data length is not the same as the expected
     *             total.
     */
    @Override
    public int read(byte[] b, int off, int len) throws IOException {
        int readLen = super.read(b, off, len);
        dataLength += readLen >= 0 ? readLen : 0;
        checkLength(readLen == -1);
        return readLen;
    }

    @Override
    public void mark(int readlimit) {
        super.mark(readlimit);
        marked = dataLength;
    }

    @Override
    public void reset() throws IOException {
        super.reset();
        if (super.markSupported()) {
            dataLength = marked;
        }
    }

    /**
     * Checks the data length read so far against the expected total.
     * 
     * @param eof
     *            true if end of stream has been encountered; false otherwise
     * 
     * @throws AmazonClientException
     *             if the data length read has exceeded the expected total, or
     *             if the total data length is not the same as the expected
     *             total.
     */
    private void checkLength(boolean eof) {
        if (eof) {
            if (dataLength != expectedLength) {
                throw new AmazonClientException("Data read (" + dataLength
                        + ") has a different length than the expected ("
                        + expectedLength + ")");
            }
        } else if (dataLength > expectedLength) {
            throw new AmazonClientException("More data read (" + dataLength
                    + ") than expected (" + expectedLength + ")");
        }
    }

    /**
     * {@inheritDoc}
     * 
     * @throws AmazonClientException
     *             if {@link #includeSkipped} is true and the data length
     *             skipped has exceeded the expected total.
     */
    @Override
    public long skip(long n) throws IOException {
        final long skipped = super.skip(n);
        if (includeSkipped && skipped > 0) {
            dataLength += skipped;
            checkLength(false);
        }
        return skipped;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy