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: 480424 $
    4    * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
    5    *
    6    * ====================================================================
    7    *
    8    *  Licensed to the Apache Software Foundation (ASF) under one or more
    9    *  contributor license agreements.  See the NOTICE file distributed with
    10   *  this work for additional information regarding copyright ownership.
    11   *  The ASF licenses this file to You under the Apache License, Version 2.0
    12   *  (the "License"); you may not use this file except in compliance with
    13   *  the License.  You may obtain a copy of the License at
    14   *
    15   *      http://www.apache.org/licenses/LICENSE-2.0
    16   *
    17   *  Unless required by applicable law or agreed to in writing, software
    18   *  distributed under the License is distributed on an "AS IS" BASIS,
    19   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    20   *  See the License for the specific language governing permissions and
    21   *  limitations under the License.
    22   * ====================================================================
    23   *
    24   * This software consists of voluntary contributions made by many
    25   * individuals on behalf of the Apache Software Foundation.  For more
    26   * information on the Apache Software Foundation, please see
    27   * <http://www.apache.org/>.
    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 }