View Javadoc

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