
com.aliyun.oss.common.comm.io.ChunkedUploadStream Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aliyun-sdk-oss Show documentation
Show all versions of aliyun-sdk-oss Show documentation
The Aliyun OSS SDK for Java used for accessing Aliyun Object Storage Service
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 com.aliyun.oss.common.comm.io;
import java.io.IOException;
import java.io.InputStream;
import com.aliyun.oss.ClientException;
public class ChunkedUploadStream extends InputStream {
private static final int DEFAULT_CHUNK_SIZE = 128 * 1024;
private static final String DEFAULT_CHARTSET_NAME = "utf-8";
private static final String CLRF = "\r\n";
private InputStream innerStream;
private byte[] inputBuffer;
private byte[] outputBuffer;
private int outputBufferPos = -1;
private int outputBufferDataLen = -1;
private final int innerStreamBufferSize;
private boolean innerStreamConsumed = false;
private boolean isTerminatingChunk = false;
public ChunkedUploadStream(InputStream innerStream, int innerStreamBufferSize) {
if (innerStream == null) {
throw new IllegalArgumentException("Source input stream should not be null");
}
this.innerStream = innerStream;
this.innerStreamBufferSize = innerStreamBufferSize;
this.inputBuffer = new byte[DEFAULT_CHUNK_SIZE];
this.outputBuffer = new byte[CalculateChunkHeaderLength(DEFAULT_CHUNK_SIZE)];
}
@Override
public int read() throws IOException {
byte[] tmp = new byte[1];
int count = read(tmp);
if (count != -1) {
return tmp[0];
} else {
return count;
}
}
@Override
public int read(byte[] buffer) throws IOException {
return read(buffer, 0, buffer.length);
}
@Override
public int read(byte[] buffer, int offset, int count) throws IOException {
if (buffer == null) {
throw new NullPointerException();
} else if (offset < 0 || count < 0 || count > buffer.length - offset) {
throw new IndexOutOfBoundsException(
String.format("buffer size: %n, offset: %n, count: %n", buffer.length, offset, count));
} else if (count == 0) {
return 0;
}
if (outputBufferPos == -1) {
if (innerStreamConsumed && isTerminatingChunk) {
return -1;
}
int bytesRead = fillInputBuffer();
constructOutputBufferChunk(bytesRead);
isTerminatingChunk = (innerStreamConsumed && bytesRead == 0);
}
int outputRemaining = outputBufferDataLen - outputBufferPos;
int bytesToRead = count;
if (outputRemaining < count) {
bytesToRead = outputRemaining;
}
System.arraycopy(outputBuffer, outputBufferPos, buffer, 0, bytesToRead);
outputBufferPos += bytesToRead;
if (outputBufferPos >= outputBufferDataLen) {
outputBufferPos = -1;
}
return bytesToRead;
}
private int fillInputBuffer() {
if (innerStreamConsumed) {
return 0;
}
int inputBufferPos = 0;
while (inputBufferPos < inputBuffer.length && !innerStreamConsumed) {
int chunkBufferRemaining = inputBuffer.length - inputBufferPos;
if (chunkBufferRemaining > innerStreamBufferSize) {
chunkBufferRemaining = innerStreamBufferSize;
}
int bytesRead = 0;
try {
bytesRead = innerStream.read(inputBuffer, inputBufferPos, chunkBufferRemaining);
if (bytesRead == -1) {
innerStreamConsumed = true;
} else {
inputBufferPos += bytesRead;
}
} catch (IOException e) {
throw new ClientException("Unexpected IO exception, " + e.getMessage(), e);
}
}
return inputBufferPos;
}
private void constructOutputBufferChunk(int dataLen) {
StringBuilder chunkHeader = new StringBuilder();
chunkHeader.append(Integer.toHexString(dataLen));
chunkHeader.append(CLRF);
try {
byte[] header = chunkHeader.toString().getBytes(DEFAULT_CHARTSET_NAME);
byte[] trailer = CLRF.getBytes(DEFAULT_CHARTSET_NAME);
int writePos = 0;
System.arraycopy(header, 0, outputBuffer, writePos, header.length);
writePos += header.length;
if (dataLen > 0) {
System.arraycopy(inputBuffer, 0, outputBuffer, writePos, dataLen);
writePos += dataLen;
}
System.arraycopy(trailer, 0, outputBuffer, writePos, trailer.length);
outputBufferPos = 0;
outputBufferDataLen = header.length + dataLen + trailer.length;
} catch (Exception e) {
throw new ClientException("Unable to sign the chunked data, " + e.getMessage(), e);
}
}
private static int CalculateChunkHeaderLength(long chunkDataSize) {
return (int) (Long.toHexString(chunkDataSize).length() + CLRF.length() + chunkDataSize + CLRF.length());
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy