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.File;
34 import java.io.FileNotFoundException;
35 import java.io.IOException;
36 import java.io.OutputStream;
37 import java.util.ArrayList;
38 import java.util.List;
39
40 import org.apache.commons.httpclient.HttpConnection;
41 import org.apache.commons.httpclient.HttpException;
42 import org.apache.commons.httpclient.HttpState;
43 import org.apache.commons.httpclient.methods.multipart.FilePart;
44 import org.apache.commons.httpclient.methods.multipart.Part;
45 import org.apache.commons.httpclient.methods.multipart.StringPart;
46 import org.apache.commons.logging.Log;
47 import org.apache.commons.logging.LogFactory;
48
49 /***
50 * Implements the HTTP multipart POST method.
51 * <p>
52 * The HTTP multipart POST method is defined in section 3.3 of
53 * <a href="http://www.ietf.org/rfc/rfc1867.txt">RFC1867</a>:
54 * <blockquote>
55 * The media-type multipart/form-data follows the rules of all multipart
56 * MIME data streams as outlined in RFC 1521. The multipart/form-data contains
57 * a series of parts. Each part is expected to contain a content-disposition
58 * header where the value is "form-data" and a name attribute specifies
59 * the field name within the form, e.g., 'content-disposition: form-data;
60 * name="xxxxx"', where xxxxx is the field name corresponding to that field.
61 * Field names originally in non-ASCII character sets may be encoded using
62 * the method outlined in RFC 1522.
63 * </blockquote>
64 * </p>
65 * <p>
66 *
67 * @author <a href="mailto:mattalbright@yahoo.com">Matthew Albright</a>
68 * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
69 * @author <a href="mailto:adrian@ephox.com">Adrian Sutton</a>
70 * @author <a href="mailto:mdiggory@latte.harvard.edu">Mark Diggory</a>
71 * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
72 * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
73 *
74 * @since 2.0
75 *
76 * @deprecated Use {@link org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity}
77 * in conjunction with {@link org.apache.commons.httpclient.methods.PostMethod} instead.
78 */
79 public class MultipartPostMethod extends ExpectContinueMethod {
80
81 /*** The Content-Type for multipart/form-data. */
82 public static final String MULTIPART_FORM_CONTENT_TYPE =
83 "multipart/form-data";
84
85 /*** Log object for this class. */
86 private static final Log LOG = LogFactory.getLog(MultipartPostMethod.class);
87
88 /*** The parameters for this method */
89 private final List parameters = new ArrayList();
90
91 /***
92 * No-arg constructor.
93 */
94 public MultipartPostMethod() {
95 super();
96 }
97
98 /***
99 * Constructor specifying a URI.
100 *
101 * @param uri either an absolute or relative URI
102 */
103 public MultipartPostMethod(String uri) {
104 super(uri);
105 }
106
107 /***
108 * Returns <tt>true</tt>
109 *
110 * @return <tt>true</tt>
111 *
112 * @since 2.0beta1
113 */
114 protected boolean hasRequestContent() {
115 return true;
116 }
117
118 /***
119 * Returns <tt>"POST"</tt>.
120 * @return <tt>"POST"</tt>
121 */
122 public String getName() {
123 return "POST";
124 }
125
126 /***
127 * Adds a text field part
128 *
129 * @param parameterName The name of the parameter.
130 * @param parameterValue The value of the parameter.
131 */
132 public void addParameter(String parameterName, String parameterValue) {
133 LOG.trace("enter addParameter(String parameterName, String parameterValue)");
134 Part param = new StringPart(parameterName, parameterValue);
135 parameters.add(param);
136 }
137
138 /***
139 * Adds a binary file part
140 *
141 * @param parameterName The name of the parameter
142 * @param parameterFile The name of the file.
143 * @throws FileNotFoundException If the file cannot be found.
144 */
145 public void addParameter(String parameterName, File parameterFile)
146 throws FileNotFoundException {
147 LOG.trace("enter MultipartPostMethod.addParameter(String parameterName, "
148 + "File parameterFile)");
149 Part param = new FilePart(parameterName, parameterFile);
150 parameters.add(param);
151 }
152
153 /***
154 * Adds a binary file part with the given file name
155 *
156 * @param parameterName The name of the parameter
157 * @param fileName The file name
158 * @param parameterFile The file
159 * @throws FileNotFoundException If the file cannot be found.
160 */
161 public void addParameter(String parameterName, String fileName, File parameterFile)
162 throws FileNotFoundException {
163 LOG.trace("enter MultipartPostMethod.addParameter(String parameterName, "
164 + "String fileName, File parameterFile)");
165 Part param = new FilePart(parameterName, fileName, parameterFile);
166 parameters.add(param);
167 }
168
169 /***
170 * Adds a part.
171 *
172 * @param part The part to add.
173 */
174 public void addPart (final Part part) {
175 LOG.trace("enter addPart(Part part)");
176 parameters.add(part);
177 }
178
179 /***
180 * Returns all parts.
181 *
182 * @return an array of containing all parts
183 */
184 public Part[] getParts() {
185 return (Part[]) parameters.toArray(new Part[parameters.size()]);
186 }
187
188 /***
189 * Adds a <tt>Content-Length</tt> request header, as long as no
190 * <tt>Content-Length</tt> request header already exists.
191 *
192 * @param state current state of http requests
193 * @param conn the connection to use for I/O
194 *
195 * @throws IOException if an I/O (transport) error occurs. Some transport exceptions
196 * can be recovered from.
197 * @throws HttpException if a protocol exception occurs. Usually protocol exceptions
198 * cannot be recovered from.
199 *
200 * @since 3.0
201 */
202 protected void addContentLengthRequestHeader(HttpState state,
203 HttpConnection conn)
204 throws IOException, HttpException {
205 LOG.trace("enter EntityEnclosingMethod.addContentLengthRequestHeader("
206 + "HttpState, HttpConnection)");
207
208 if (getRequestHeader("Content-Length") == null) {
209 long len = getRequestContentLength();
210 addRequestHeader("Content-Length", String.valueOf(len));
211 }
212 removeRequestHeader("Transfer-Encoding");
213 }
214
215 /***
216 * Adds a <tt>Content-Type</tt> request header.
217 *
218 * @param state current state of http requests
219 * @param conn the connection to use for I/O
220 *
221 * @throws IOException if an I/O (transport) error occurs. Some transport exceptions
222 * can be recovered from.
223 * @throws HttpException if a protocol exception occurs. Usually protocol exceptions
224 * cannot be recovered from.
225 *
226 * @since 3.0
227 */
228 protected void addContentTypeRequestHeader(HttpState state,
229 HttpConnection conn)
230 throws IOException, HttpException {
231 LOG.trace("enter EntityEnclosingMethod.addContentTypeRequestHeader("
232 + "HttpState, HttpConnection)");
233
234 if (!parameters.isEmpty()) {
235 StringBuffer buffer = new StringBuffer(MULTIPART_FORM_CONTENT_TYPE);
236 if (Part.getBoundary() != null) {
237 buffer.append("; boundary=");
238 buffer.append(Part.getBoundary());
239 }
240 setRequestHeader("Content-Type", buffer.toString());
241 }
242 }
243
244 /***
245 * Populates the request headers map to with additional
246 * {@link org.apache.commons.httpclient.Header headers} to be submitted to
247 * the given {@link HttpConnection}.
248 *
249 * <p>
250 * This implementation adds tt>Content-Length</tt> and <tt>Content-Type</tt>
251 * headers, when appropriate.
252 * </p>
253 *
254 * <p>
255 * Subclasses may want to override this method to to add additional
256 * headers, and may choose to invoke this implementation (via
257 * <tt>super</tt>) to add the "standard" headers.
258 * </p>
259 *
260 * @param state the {@link HttpState state} information associated with this method
261 * @param conn the {@link HttpConnection connection} used to execute
262 * this HTTP method
263 *
264 * @throws IOException if an I/O (transport) error occurs. Some transport exceptions
265 * can be recovered from.
266 * @throws HttpException if a protocol exception occurs. Usually protocol exceptions
267 * cannot be recovered from.
268 *
269 * @see #writeRequestHeaders
270 */
271 protected void addRequestHeaders(HttpState state, HttpConnection conn)
272 throws IOException, HttpException {
273 LOG.trace("enter MultipartPostMethod.addRequestHeaders(HttpState state, "
274 + "HttpConnection conn)");
275 super.addRequestHeaders(state, conn);
276 addContentLengthRequestHeader(state, conn);
277 addContentTypeRequestHeader(state, conn);
278 }
279
280 /***
281 * Writes the request body to the given {@link HttpConnection connection}.
282 *
283 * @param state the {@link HttpState state} information associated with this method
284 * @param conn the {@link HttpConnection connection} used to execute
285 * this HTTP method
286 *
287 * @return <tt>true</tt>
288 *
289 * @throws IOException if an I/O (transport) error occurs. Some transport exceptions
290 * can be recovered from.
291 * @throws HttpException if a protocol exception occurs. Usually protocol exceptions
292 * cannot be recovered from.
293 */
294 protected boolean writeRequestBody(HttpState state, HttpConnection conn)
295 throws IOException, HttpException {
296 LOG.trace("enter MultipartPostMethod.writeRequestBody(HttpState state, "
297 + "HttpConnection conn)");
298 OutputStream out = conn.getRequestOutputStream();
299 Part.sendParts(out, getParts());
300 return true;
301 }
302
303 /***
304 * <p>Return the length of the request body.</p>
305 *
306 * <p>Once this method has been invoked, the request parameters cannot be
307 * altered until the method is {@link #recycle recycled}.</p>
308 *
309 * @return The request content length.
310 */
311 protected long getRequestContentLength() throws IOException {
312 LOG.trace("enter MultipartPostMethod.getRequestContentLength()");
313 return Part.getLengthOfParts(getParts());
314 }
315
316
317 /***
318 * Recycles the HTTP method so that it can be used again.
319 * Note that all of the instance variables will be reset
320 * once this method has been called. This method will also
321 * release the connection being used by this HTTP method.
322 *
323 * @see #releaseConnection()
324 *
325 * @deprecated no longer supported and will be removed in the future
326 * version of HttpClient
327 */
328 public void recycle() {
329 LOG.trace("enter MultipartPostMethod.recycle()");
330 super.recycle();
331 parameters.clear();
332 }
333 }