com.kingsoft.services.http.impl.RepeatableInputStreamRequestEntity Maven / Gradle / Ivy
package com.kingsoft.services.http.impl;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.http.entity.BasicHttpEntity;
import org.apache.http.entity.InputStreamEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.kingsoft.services.HttpHeaders;
import com.kingsoft.services.RequestMessage;
public class RepeatableInputStreamRequestEntity extends BasicHttpEntity {
/** True if the request entity hasn't been written out yet */
private boolean firstAttempt = true;
/** The underlying InputStreamEntity being delegated to */
private InputStreamEntity inputStreamRequestEntity;
/** The InputStream containing the content to write out */
private InputStream content;
private static final Logger log = LoggerFactory
.getLogger(RepeatableInputStreamRequestEntity.class);
/**
* Record the original exception if we do attempt a retry, so that if the
* retry fails, we can report the original exception. Otherwise, we're most
* likely masking the real exception with an error about not being able to
* reset far enough back in the input stream.
*/
private IOException originalException;
public RepeatableInputStreamRequestEntity(final RequestMessage> request) {
setChunked(false);
/*
* If we don't specify a content length when we instantiate our
* InputStreamRequestEntity, then HttpClient will attempt to buffer the
* entire stream contents into memory to determine the content length.
*
* TODO: It'd be nice to have easier access to content length and
* content type from the request, instead of having to look directly
* into the headers.
*/
long contentLength = -1;
try {
String contentLengthString = request.getHeaders().get(
HttpHeaders.CONTENT_LENGTH);
if (contentLengthString != null) {
contentLength = Long.parseLong(contentLengthString);
} else {
throw new IllegalStateException(String.format(
"can not find %s header", HttpHeaders.CONTENT_LENGTH));
}
} catch (NumberFormatException nfe) {
log.error("Unable to parse content length from request. "
+ "Buffering contents in memory.");
throw nfe;
}
String contentType = request.getHeaders().get("Content-Type");
inputStreamRequestEntity = new InputStreamEntity(request.getContent(),
contentLength);
inputStreamRequestEntity.setContentType(contentType);
content = request.getContent();
setContent(content);
setContentType(contentType);
setContentLength(contentLength);
}
@Override
public boolean isChunked() {
return false;
}
/**
* Returns true if the underlying InputStream supports marking/reseting or
* if the underlying InputStreamRequestEntity is repeatable (i.e. its
* content length has been set to
* {@link InputStreamRequestEntity#CONTENT_LENGTH_AUTO} and therefore its
* entire contents will be buffered in memory and can be repeated).
*
* @see org.apache.commons.httpclient.methods.RequestEntity#isRepeatable()
*/
@Override
public boolean isRepeatable() {
return content.markSupported()
|| inputStreamRequestEntity.isRepeatable();
}
/**
* Resets the underlying InputStream if this isn't the first attempt to
* write out the request, otherwise simply delegates to
* InputStreamRequestEntity to write out the data.
*
* If an error is encountered the first time we try to write the request
* entity, we remember the original exception, and report that as the root
* cause if we continue to encounter errors, rather than masking the
* original error.
*
* @see org.apache.commons.httpclient.methods.RequestEntity#writeRequest(java.io.OutputStream)
*/
@Override
public void writeTo(OutputStream output) throws IOException {
try {
if (!firstAttempt && isRepeatable())
content.reset();
firstAttempt = false;
inputStreamRequestEntity.writeTo(output);
} catch (IOException ioe) {
if (originalException == null)
originalException = ioe;
throw originalException;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy