View Javadoc

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