/* * Copyright 2010 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.http; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import org.apache.commons.httpclient.methods.InputStreamRequestEntity; import org.apache.commons.httpclient.methods.RequestEntity; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Custom implementation of {@link RequestEntity} that delegates to an * {@link InputStreamRequestEntity}, with the one notable difference, that if * the underlying InputStream supports being reset, this RequestEntity will * report that it is repeatable and will reset the stream on all subsequent * attempts to write out the request. */ class RepeatableInputStreamRequestEntity implements RequestEntity { /** True if the request entity hasn't been written out yet */ private boolean firstAttempt = true; /** The underlying InputStreamRequestEntity being delegated to */ private InputStreamRequestEntity inputStreamRequestEntity; /** The InputStream containing the content to write out */ private InputStream content; /** Shared logger for more debugging information */ private static final Log log = LogFactory.getLog(HttpClient.class); /** * Creates a new RepeatableInputStreamRequestEntity using the information * from the specified request. If the input stream containing the request's * contents is repeatable, then this RequestEntity will report as being * repeatable. * * @param request * The details of the request being written out (content type, * content length, and content). */ RepeatableInputStreamRequestEntity(HttpRequest request) { /* * 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 = InputStreamRequestEntity.CONTENT_LENGTH_AUTO; try { String contentLengthString = request.getHeaders().get("Content-Length"); if (contentLengthString != null) { contentLength = Long.parseLong(contentLengthString); } } catch (NumberFormatException nfe) { log.warn("Unable to parse content length from request. " + "Buffering contents in memory."); } String contentType = request.getHeaders().get("Content-Type"); inputStreamRequestEntity = new InputStreamRequestEntity( request.getContent(), contentLength, contentType); content = request.getContent(); } /** * Delegates to the underlying InputStreamRequestEntity. * * @see org.apache.commons.httpclient.methods.RequestEntity#getContentType() */ public String getContentType() { return inputStreamRequestEntity.getContentType(); } /** * 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() */ 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. * * @see org.apache.commons.httpclient.methods.RequestEntity#writeRequest(java.io.OutputStream) */ public void writeRequest(OutputStream output) throws IOException { if (!firstAttempt && isRepeatable()) { content.reset(); } firstAttempt = false; inputStreamRequestEntity.writeRequest(output); } /** * Delegates to the underlying InputStreamRequestEntity. * * @see org.apache.commons.httpclient.methods.RequestEntity#getContentLength() */ public long getContentLength() { return inputStreamRequestEntity.getContentLength(); } }