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 any of
89 * {@link EntityEnclosingMethod#CONTENT_LENGTH_AUTO CONTENT_LENGTH_AUTO},
90 * {@link EntityEnclosingMethod#CONTENT_LENGTH_CHUNKED CONTENT_LENGTH_CHUNKED}. If the number
91 * of bytes or <code>CONTENT_LENGTH_CHUNKED</code> is specified the content will not be
92 * buffered when {@link #getContentLength()} is called.
93 */
94 public InputStreamRequestEntity(InputStream content, long contentLength) {
95 this(content, contentLength, null);
96 }
97
98 /***
99 * Creates a new InputStreamRequestEntity with the given content, content length, and
100 * content type.
101 * @param content The content to set.
102 * @param contentLength The content size in bytes or any of
103 * {@link EntityEnclosingMethod#CONTENT_LENGTH_AUTO CONTENT_LENGTH_AUTO},
104 * {@link EntityEnclosingMethod#CONTENT_LENGTH_CHUNKED CONTENT_LENGTH_CHUNKED}. If the number
105 * of bytes or <code>CONTENT_LENGTH_CHUNKED</code> is specified the content will not be
106 * buffered when {@link #getContentLength()} is called.
107 * @param contentType The type of the content, or <code>null</code>.
108 */
109 public InputStreamRequestEntity(InputStream content, long contentLength, String contentType) {
110 if (content == null) {
111 throw new IllegalArgumentException("The content cannot be null");
112 }
113 this.content = content;
114 this.contentLength = contentLength;
115 this.contentType = contentType;
116 }
117
118
119
120
121 public String getContentType() {
122 return contentType;
123 }
124
125 /***
126 * Buffers request body input stream.
127 */
128 private void bufferContent() {
129
130 if (this.buffer != null) {
131
132 return;
133 }
134 if (this.content != null) {
135 try {
136 ByteArrayOutputStream tmp = new ByteArrayOutputStream();
137 byte[] data = new byte[4096];
138 int l = 0;
139 while ((l = this.content.read(data)) >= 0) {
140 tmp.write(data, 0, l);
141 }
142 this.buffer = tmp.toByteArray();
143 this.content = null;
144 this.contentLength = buffer.length;
145 } catch (IOException e) {
146 LOG.error(e.getMessage(), e);
147 this.buffer = null;
148 this.content = null;
149 this.contentLength = 0;
150 }
151 }
152 }
153
154 /***
155 * Tests if this method is repeatable. Only <code>true</code> if the content has been
156 * buffered.
157 *
158 * @see #getContentLength()
159 */
160 public boolean isRepeatable() {
161 return buffer != null;
162 }
163
164
165
166
167 public void writeRequest(OutputStream out) throws IOException {
168
169 if (content != null) {
170 byte[] tmp = new byte[4096];
171 int total = 0;
172 int i = 0;
173 while ((i = content.read(tmp)) >= 0) {
174 out.write(tmp, 0, i);
175 total += i;
176 }
177 } else if (buffer != null) {
178 out.write(buffer);
179 } else {
180 throw new IllegalStateException("Content must be set before entity is written");
181 }
182 }
183
184 /***
185 * Gets the content length. If the content length has not been set, the content will be
186 * buffered to determine the actual content length.
187 */
188 public long getContentLength() {
189 if (contentLength == CONTENT_LENGTH_AUTO && buffer == null) {
190 bufferContent();
191 }
192 return contentLength;
193 }
194
195 /***
196 * @return Returns the content.
197 */
198 public InputStream getContent() {
199 return content;
200 }
201
202 }