1. /*
  2. * $Header: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/InputStreamRequestEntity.java,v 1.4 2004/05/17 21:46:03 olegk Exp $
  3. * $Revision: 1.4 $
  4. * $Date: 2004/05/17 21:46:03 $
  5. *
  6. * ====================================================================
  7. *
  8. * Copyright 2004 The Apache Software Foundation
  9. *
  10. * Licensed under the Apache License, Version 2.0 (the "License");
  11. * you may not use this file except in compliance with the License.
  12. * You may obtain a copy of the License at
  13. *
  14. * http://www.apache.org/licenses/LICENSE-2.0
  15. *
  16. * Unless required by applicable law or agreed to in writing, software
  17. * distributed under the License is distributed on an "AS IS" BASIS,
  18. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  19. * See the License for the specific language governing permissions and
  20. * limitations under the License.
  21. * ====================================================================
  22. *
  23. * This software consists of voluntary contributions made by many
  24. * individuals on behalf of the Apache Software Foundation. For more
  25. * information on the Apache Software Foundation, please see
  26. * <http://www.apache.org/>.
  27. *
  28. * [Additional notices, if required by prior licensing conditions]
  29. *
  30. */
  31. package org.apache.commons.httpclient.methods;
  32. import java.io.ByteArrayOutputStream;
  33. import java.io.IOException;
  34. import java.io.InputStream;
  35. import java.io.OutputStream;
  36. import org.apache.commons.logging.Log;
  37. import org.apache.commons.logging.LogFactory;
  38. /**
  39. * A RequestEntity that contains an InputStream.
  40. *
  41. * @since 3.0
  42. */
  43. public class InputStreamRequestEntity implements RequestEntity {
  44. /**
  45. * The content length will be calculated automatically. This implies
  46. * buffering of the content.
  47. */
  48. public static final int CONTENT_LENGTH_AUTO = -2;
  49. private static final Log LOG = LogFactory.getLog(InputStreamRequestEntity.class);
  50. private long contentLength;
  51. private InputStream content;
  52. /** The buffered request body, if any. */
  53. private byte[] buffer = null;
  54. /** The content type */
  55. private String contentType;
  56. /**
  57. * Creates a new InputStreamRequestEntity with the given content and a content type of
  58. * {@link #CONTENT_LENGTH_AUTO}.
  59. * @param content The content to set.
  60. */
  61. public InputStreamRequestEntity(InputStream content) {
  62. this(content, null);
  63. }
  64. /**
  65. * Creates a new InputStreamRequestEntity with the given content, content type, and a
  66. * content length of {@link #CONTENT_LENGTH_AUTO}.
  67. * @param content The content to set.
  68. * @param contentType The type of the content, or <code>null</code>.
  69. */
  70. public InputStreamRequestEntity(InputStream content, String contentType) {
  71. this(content, CONTENT_LENGTH_AUTO, contentType);
  72. }
  73. /**
  74. * Creates a new InputStreamRequestEntity with the given content and content length.
  75. * @param content The content to set.
  76. * @param contentLength The content size in bytes or any of
  77. * {@link EntityEnclosingMethod#CONTENT_LENGTH_AUTO CONTENT_LENGTH_AUTO},
  78. * {@link EntityEnclosingMethod#CONTENT_LENGTH_CHUNKED CONTENT_LENGTH_CHUNKED}. If the number
  79. * of bytes or <code>CONTENT_LENGTH_CHUNKED</code> is specified the content will not be
  80. * buffered when {@link #getContentLength()} is called.
  81. */
  82. public InputStreamRequestEntity(InputStream content, long contentLength) {
  83. this(content, contentLength, null);
  84. }
  85. /**
  86. * Creates a new InputStreamRequestEntity with the given content, content length, and
  87. * content type.
  88. * @param content The content to set.
  89. * @param contentLength The content size in bytes or any of
  90. * {@link EntityEnclosingMethod#CONTENT_LENGTH_AUTO CONTENT_LENGTH_AUTO},
  91. * {@link EntityEnclosingMethod#CONTENT_LENGTH_CHUNKED CONTENT_LENGTH_CHUNKED}. If the number
  92. * of bytes or <code>CONTENT_LENGTH_CHUNKED</code> is specified the content will not be
  93. * buffered when {@link #getContentLength()} is called.
  94. * @param contentType The type of the content, or <code>null</code>.
  95. */
  96. public InputStreamRequestEntity(InputStream content, long contentLength, String contentType) {
  97. if (content == null) {
  98. throw new IllegalArgumentException("The content cannot be null");
  99. }
  100. this.content = content;
  101. this.contentLength = contentLength;
  102. this.contentType = contentType;
  103. }
  104. /* (non-Javadoc)
  105. * @see org.apache.commons.httpclient.methods.RequestEntity#getContentType()
  106. */
  107. public String getContentType() {
  108. return contentType;
  109. }
  110. /**
  111. * Buffers request body input stream.
  112. */
  113. private void bufferContent() {
  114. if (this.buffer != null) {
  115. // Already been buffered
  116. return;
  117. }
  118. if (this.content != null) {
  119. try {
  120. ByteArrayOutputStream tmp = new ByteArrayOutputStream();
  121. byte[] data = new byte[4096];
  122. int l = 0;
  123. while ((l = this.content.read(data)) >= 0) {
  124. tmp.write(data, 0, l);
  125. }
  126. this.buffer = tmp.toByteArray();
  127. this.content = null;
  128. this.contentLength = buffer.length;
  129. } catch (IOException e) {
  130. LOG.error(e.getMessage(), e);
  131. this.buffer = null;
  132. this.content = null;
  133. this.contentLength = 0;
  134. }
  135. }
  136. }
  137. /**
  138. * Tests if this method is repeatable. Only <code>true</code> if the content has been
  139. * buffered.
  140. *
  141. * @see #getContentLength()
  142. */
  143. public boolean isRepeatable() {
  144. return content != null;
  145. }
  146. /* (non-Javadoc)
  147. * @see org.apache.commons.httpclient.RequestEntity#writeRequest(java.io.OutputStream)
  148. */
  149. public void writeRequest(OutputStream out) throws IOException {
  150. if (content != null) {
  151. byte[] tmp = new byte[4096];
  152. int total = 0;
  153. int i = 0;
  154. while ((i = content.read(tmp)) >= 0) {
  155. out.write(tmp, 0, i);
  156. total += i;
  157. }
  158. } else if (buffer != null) {
  159. out.write(buffer);
  160. } else {
  161. throw new IllegalStateException("Content must be set before entity is written");
  162. }
  163. }
  164. /**
  165. * Gets the content length. If the content length has not been set, the content will be
  166. * buffered to determine the actual content length.
  167. */
  168. public long getContentLength() {
  169. if (contentLength == CONTENT_LENGTH_AUTO && buffer == null) {
  170. bufferContent();
  171. }
  172. return contentLength;
  173. }
  174. /**
  175. * @return Returns the content.
  176. */
  177. public InputStream getContent() {
  178. return content;
  179. }
  180. }