1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 package org.apache.commons.httpclient.methods;
32
33 import java.io.ByteArrayOutputStream;
34 import java.io.IOException;
35 import java.io.InputStream;
36 import java.io.OutputStream;
37
38 import org.apache.commons.logging.Log;
39 import org.apache.commons.logging.LogFactory;
40
41 /***
42 * A RequestEntity that contains an InputStream.
43 *
44 * @since 3.0
45 */
46 public class InputStreamRequestEntity implements RequestEntity {
47
48 /***
49 * The content length will be calculated automatically. This implies
50 * buffering of the content.
51 */
52 public static final int CONTENT_LENGTH_AUTO = -2;
53
54 private static final Log LOG = LogFactory.getLog(InputStreamRequestEntity.class);
55
56 private long contentLength;
57
58 private InputStream content;
59
60 /*** The buffered request body, if any. */
61 private byte[] buffer = null;
62
63 /*** The content type */
64 private String contentType;
65
66 /***
67 * Creates a new InputStreamRequestEntity with the given content and a content type of
68 * {@link #CONTENT_LENGTH_AUTO}.
69 * @param content The content to set.
70 */
71 public InputStreamRequestEntity(InputStream content) {
72 this(content, null);
73 }
74
75 /***
76 * Creates a new InputStreamRequestEntity with the given content, content type, and a
77 * content length of {@link #CONTENT_LENGTH_AUTO}.
78 * @param content The content to set.
79 * @param contentType The type of the content, or <code>null</code>.
80 */
81 public InputStreamRequestEntity(InputStream content, String contentType) {
82 this(content, CONTENT_LENGTH_AUTO, contentType);
83 }
84
85 /***
86 * Creates a new InputStreamRequestEntity with the given content and content length.
87 * @param content The content to set.
88 * @param contentLength The content size in bytes or a negative number if not known.
89 * If {@link #CONTENT_LENGTH_AUTO} is given the content will be buffered in order to
90 * determine its size when {@link #getContentLength()} is called.
91 */
92 public InputStreamRequestEntity(InputStream content, long contentLength) {
93 this(content, contentLength, null);
94 }
95
96 /***
97 * Creates a new InputStreamRequestEntity with the given content, content length, and
98 * content type.
99 * @param content The content to set.
100 * @param contentLength The content size in bytes or a negative number if not known.
101 * If {@link #CONTENT_LENGTH_AUTO} is given the content will be buffered in order to
102 * determine its size when {@link #getContentLength()} is called.
103 * @param contentType The type of the content, or <code>null</code>.
104 */
105 public InputStreamRequestEntity(InputStream content, long contentLength, String contentType) {
106 if (content == null) {
107 throw new IllegalArgumentException("The content cannot be null");
108 }
109 this.content = content;
110 this.contentLength = contentLength;
111 this.contentType = contentType;
112 }
113
114
115
116
117 public String getContentType() {
118 return contentType;
119 }
120
121 /***
122 * Buffers request body input stream.
123 */
124 private void bufferContent() {
125
126 if (this.buffer != null) {
127
128 return;
129 }
130 if (this.content != null) {
131 try {
132 ByteArrayOutputStream tmp = new ByteArrayOutputStream();
133 byte[] data = new byte[4096];
134 int l = 0;
135 while ((l = this.content.read(data)) >= 0) {
136 tmp.write(data, 0, l);
137 }
138 this.buffer = tmp.toByteArray();
139 this.content = null;
140 this.contentLength = buffer.length;
141 } catch (IOException e) {
142 LOG.error(e.getMessage(), e);
143 this.buffer = null;
144 this.content = null;
145 this.contentLength = 0;
146 }
147 }
148 }
149
150 /***
151 * Tests if this method is repeatable. Only <code>true</code> if the content has been
152 * buffered.
153 *
154 * @see #getContentLength()
155 */
156 public boolean isRepeatable() {
157 return buffer != null;
158 }
159
160
161
162
163 public void writeRequest(OutputStream out) throws IOException {
164
165 if (content != null) {
166 byte[] tmp = new byte[4096];
167 int total = 0;
168 int i = 0;
169 while ((i = content.read(tmp)) >= 0) {
170 out.write(tmp, 0, i);
171 total += i;
172 }
173 } else if (buffer != null) {
174 out.write(buffer);
175 } else {
176 throw new IllegalStateException("Content must be set before entity is written");
177 }
178 }
179
180 /***
181 * Gets the content length. If the content length has not been set, the content will be
182 * buffered to determine the actual content length.
183 */
184 public long getContentLength() {
185 if (contentLength == CONTENT_LENGTH_AUTO && buffer == null) {
186 bufferContent();
187 }
188 return contentLength;
189 }
190
191 /***
192 * @return Returns the content.
193 */
194 public InputStream getContent() {
195 return content;
196 }
197
198 }