Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Copyright 2010-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.auth;
 import static com.amazonaws.util.StringUtils.UTF8;
 
 
 
A wrapper class of InputStream that implements chunked-encoding.
 
 public final class AwsChunkedEncodingInputStream extends SdkInputStream {
 
     protected static final String DEFAULT_ENCODING = "UTF-8";
 
     private static final int DEFAULT_CHUNK_SIZE = 128 * 1024;
     private static final int DEFAULT_BUFFER_SIZE = 256 * 1024;
 
     private static final String CLRF = "\r\n";
     private static final String CHUNK_STRING_TO_SIGN_PREFIX = "AWS4-HMAC-SHA256-PAYLOAD";
     private static final String CHUNK_SIGNATURE_HEADER = ";chunk-signature=";
     private static final int SIGNATURE_LENGTH = 64;
     private static final byte[] FINAL_CHUNK = new byte[0];
 
     private InputStream is = null;
     private final int maxBufferSize;
     private final byte[] kSigning;
     private final String dateTime;
     private final String keyPath;
     private final String headerSignature;
     private String priorChunkSignature;
     private final AWS4Signer aws4Signer;

    
Iterator on the current chunk that has been signed
 
     private ChunkContentIterator currentChunkIterator;

    
Iterator on the buffer of the decoded stream, Null if the wrapped stream is marksupported, otherwise it will be initialized when this wrapper is marked.
 
 
     private boolean isAtStart = true;
     private boolean isTerminating = false;
 
     private static final Log log = LogFactory.getLog(AwsChunkedEncodingInputStream.class);
 
     public AwsChunkedEncodingInputStream(InputStream inbyte[] kSigning,
             String datetimeString keyPathString headerSignature,
             AWS4Signer aws4Signer) {
         this(inkSigningdatetimekeyPathheaderSignatureaws4Signer);
     }

    
A wrapper of InputStream that implements pseudo-chunked-encoding. Each chunk will be buffered for the calculation of the chunk signature which is added at the head of each chunk.
The default chunk size cannot be customized, since we need to calculate the expected encoded stream length before reading the wrapped stream.
This class will use the mark() & reset() of the wrapped InputStream if they are supported, otherwise it will create a buffer for bytes read from the wrapped stream.

Parameters:
in The original InputStream.
maxBufferSize Maximum number of bytes buffered by this class.
kSigning Signing key.
datetime Datetime, as used in SigV4.
keyPath Keypath/Scope, as used in SigV4.
headerSignature The signature of the signed headers. This will be used for calculating the signature of the first chunk.
aws4Signer The AWS4Signer used for hashing and signing.
 
    public AwsChunkedEncodingInputStream(InputStream inint maxBufferSize,
            byte[] kSigningString datetimeString keyPath,
            String headerSignatureAWS4Signer aws4Signer) {
        if (in instanceof AwsChunkedEncodingInputStream) {
            // This could happen when the request is retried, and we need to re-calculate the signatures.
            AwsChunkedEncodingInputStream originalChunkedStream = (AwsChunkedEncodingInputStream)in;
            maxBufferSize = Math.max(originalChunkedStream.maxBufferSizemaxBufferSize);
             = originalChunkedStream.is;
             = originalChunkedStream.decodedStreamBuffer;
        }
        else {
             = in;
             = null;
        }
        if (maxBufferSize < )
            throw new IllegalArgumentException("Max buffer size should not be less than chunk size");
        this. = maxBufferSize;
        this. = kSigning;
        this. = datetime;
        this. = keyPath;
        this. = headerSignature;
        this. = headerSignature;
        this. = aws4Signer;
    }
    @Override
    public int read() throws IOException {
        byte[] tmp = new byte[1];
        int count = read(tmp, 0, 1);
        if (count != -1) {
            if (.isDebugEnabled())
                .debug("One byte read from the stream.");
            int unsignedByte = (inttmp[0] & 0xFF;
            return unsignedByte;
        } else {
            return count;
        }
    }
    @Override
    public int read(byte[] bint offint lenthrows IOException {
        abortIfNeeded();
        if (b == null) {
            throw new NullPointerException();
        } else if (off < 0 || len < 0 || len > b.length - off) {
            throw new IndexOutOfBoundsException();
        } else if (len == 0) {
            return 0;
        }
        if (null == 
                || !.hasNext()) {
            if ()
                return -1;
            else {
                 = setUpNextChunk();
            }
        }
        int count = .read(bofflen);
        if (count > 0) {
             = false;
            if (.isTraceEnabled())
                .trace(count + " byte read from the stream.");
        }
        return count;
    }
    @Override
    public long skip(long nthrows IOException {
        if (n <= 0) {
            return 0;
        }
        long remaining = n;
        int toskip = (int) Math.min(n);
        byte[] temp = new byte[toskip];
        while (remaining > 0) {
            int count;
            if ( (count = read(temp, 0, toskip)) < 0) {
                break;
            }
            remaining -= count;
        }
        return n - remaining;
    }

    
    @Override
    public boolean markSupported() {
        return true;
    }

    
The readlimit parameter is ignored.
    @Override
    public void mark(int readlimit) {
        abortIfNeeded();
        if ( ! )
            throw new UnsupportedOperationException("Chunk-encoded stream only supports mark() at the start of the stream.");
        if (.markSupported()) {
            if (.isDebugEnabled()) {
                .debug("AwsChunkedEncodingInputStream marked at the start of the stream "
                        + "(will directly mark the wrapped stream since it's mark-supported).");
            }
            .mark(readlimit);
        }
        else {
            if (.isDebugEnabled()) {
                .debug("AwsChunkedEncodingInputStream marked at the start of the stream "
                        + "(initializing the buffer since the wrapped stream is not mark-supported).");
            }
             = new DecodedStreamBuffer();
        }
    }

    
Reset the stream, either by resetting the wrapped stream or using the buffer created by this class.
    @Override
    public void reset() throws IOException {
        abortIfNeeded();
        // Clear up any encoded data
         = null;
        // Reset the wrapped stream if it is mark-supported,
        // otherwise use our buffered data.
        if (.markSupported()) {
            if (.isDebugEnabled())
                .debug("AwsChunkedEncodingInputStream reset "
                        + "(will reset the wrapped stream because it is mark-supported).");
            .reset();
        }
        else {
            if (.isDebugEnabled())
                .debug("AwsChunkedEncodingInputStream reset "
                        + "(will use the buffer of the decoded stream).");
            if (null == ) {
                throw new IOException("Cannot reset the stream because the mark is not set.");
            }
            .startReadBuffer();
        }
         = null;
         = true;
         = false;
    }
    public static long calculateStreamContentLength(long originalLength) {
        if (originalLength < 0) {
            throw new IllegalArgumentException("Nonnegative content length expected.");
        }
        long maxSizeChunks = originalLength / ;
        long remainingBytes =  originalLength % ;
        return maxSizeChunks * calculateSignedChunkLength()
                + (remainingBytes > 0? calculateSignedChunkLength(remainingBytes) : 0)
                + calculateSignedChunkLength(0);
    }
    private static long calculateSignedChunkLength(long chunkDataSize) {
        return Long.toHexString(chunkDataSize).length()
                + .length()
                + 
                + .length()
                + chunkDataSize
                + .length();
    }

    
Read in the next chunk of data, and create the necessary chunk extensions.

Returns:
Returns true if next chunk is the last empty chunk.
    private boolean setUpNextChunk() throws IOException {
        byte[] chunkData = new byte[];
        int chunkSizeInBytes = 0;
        while (chunkSizeInBytes < ) {
            
Read from the buffer of the decoded stream
            if (null != 
                    && .hasNext()) {
                chunkData[chunkSizeInBytes++] = .next();
            }
            
Read from the wrapped stream
            else {
                int bytesToRead =  - chunkSizeInBytes;
                int count = .read(chunkDatachunkSizeInBytesbytesToRead);
                if (count != -1) {
                    if (null != )
                        .buffer(chunkDatachunkSizeInBytescount);
                    chunkSizeInBytes += count;
                }
                else
                    break;
            }
        }
        if (chunkSizeInBytes == 0){
            byte[] signedFinalChunk = createSignedChunk();
             = new ChunkContentIterator(signedFinalChunk);
            return true;
        }
        else {
            if (chunkSizeInBytes < chunkData.length) {
                chunkData = Arrays.copyOf(chunkDatachunkSizeInBytes);
            }
            byte[] signedChunkContent = createSignedChunk(chunkData);
             = new ChunkContentIterator(signedChunkContent);
            return false;
        }
    }
    private byte[] createSignedChunk(byte[] chunkData) {
        StringBuilder chunkHeader = new StringBuilder();
        // chunk-size
        chunkHeader.append(Integer.toHexString(chunkData.length));
        // nonsig-extension
        String nonsigExtension = "";
        // sig-extension
        String chunkStringToSign =
                 + "\n" +
                 + "\n" +
                 + "\n" +
                 + "\n" +
                BinaryUtils.toHex(.hash(nonsigExtension)) + "\n" +
                BinaryUtils.toHex(.hash(chunkData));
        final String chunkSignature = BinaryUtils.toHex(.sign(
                chunkStringToSign.));
         = chunkSignature;
        chunkHeader.append(nonsigExtension +  + chunkSignature);
        chunkHeader.append();
        try {
            byte[] header = chunkHeader.toString().getBytes();
            byte[] trailer = .getBytes();
            byte[] signedChunk = new byte[header.length + chunkData.length + trailer.length];
            System.arraycopy(header, 0, signedChunk, 0, header.length);
            System.arraycopy(chunkData, 0, signedChunkheader.lengthchunkData.length);
            System.arraycopy(trailer, 0,
                    signedChunkheader.length + chunkData.length,
                    trailer.length);
            return signedChunk;
        } catch (Exception e) {
            throw new AmazonClientException("Unable to sign the chunked data. " + e.getMessage(), e);
        }
    }
    @Override
    protected InputStream getWrappedInputStream() {
        return ;
    }
New to GrepCode? Check out our FAQ X