Home | History | Annotate | Download | only in multipart
      1 /*
      2  * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/methods/multipart/FilePart.java,v 1.19 2004/04/18 23:51:37 jsdever 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 com.android.internal.http.multipart;
     32 
     33 import java.io.File;
     34 import java.io.FileNotFoundException;
     35 import java.io.IOException;
     36 import java.io.InputStream;
     37 import java.io.OutputStream;
     38 import org.apache.http.util.EncodingUtils;
     39 import org.apache.commons.logging.Log;
     40 import org.apache.commons.logging.LogFactory;
     41 
     42 /**
     43  * This class implements a part of a Multipart post object that
     44  * consists of a file.
     45  *
     46  * @author <a href="mailto:mattalbright (at) yahoo.com">Matthew Albright</a>
     47  * @author <a href="mailto:jsdever (at) apache.org">Jeff Dever</a>
     48  * @author <a href="mailto:adrian (at) ephox.com">Adrian Sutton</a>
     49  * @author <a href="mailto:becke (at) u.washington.edu">Michael Becke</a>
     50  * @author <a href="mailto:mdiggory (at) latte.harvard.edu">Mark Diggory</a>
     51  * @author <a href="mailto:mbowler (at) GargoyleSoftware.com">Mike Bowler</a>
     52  * @author <a href="mailto:oleg (at) ural.ru">Oleg Kalnichevski</a>
     53  *
     54  * @since 2.0
     55  *
     56  */
     57 public class FilePart extends PartBase {
     58 
     59     /** Default content encoding of file attachments. */
     60     public static final String DEFAULT_CONTENT_TYPE = "application/octet-stream";
     61 
     62     /** Default charset of file attachments. */
     63     public static final String DEFAULT_CHARSET = "ISO-8859-1";
     64 
     65     /** Default transfer encoding of file attachments. */
     66     public static final String DEFAULT_TRANSFER_ENCODING = "binary";
     67 
     68     /** Log object for this class. */
     69     private static final Log LOG = LogFactory.getLog(FilePart.class);
     70 
     71     /** Attachment's file name */
     72     protected static final String FILE_NAME = "; filename=";
     73 
     74     /** Attachment's file name as a byte array */
     75     private static final byte[] FILE_NAME_BYTES =
     76         EncodingUtils.getAsciiBytes(FILE_NAME);
     77 
     78     /** Source of the file part. */
     79     private PartSource source;
     80 
     81     /**
     82      * FilePart Constructor.
     83      *
     84      * @param name the name for this part
     85      * @param partSource the source for this part
     86      * @param contentType the content type for this part, if <code>null</code> the
     87      * {@link #DEFAULT_CONTENT_TYPE default} is used
     88      * @param charset the charset encoding for this part, if <code>null</code> the
     89      * {@link #DEFAULT_CHARSET default} is used
     90      */
     91     public FilePart(String name, PartSource partSource, String contentType, String charset) {
     92 
     93         super(
     94             name,
     95             contentType == null ? DEFAULT_CONTENT_TYPE : contentType,
     96             charset == null ? "ISO-8859-1" : charset,
     97             DEFAULT_TRANSFER_ENCODING
     98         );
     99 
    100         if (partSource == null) {
    101             throw new IllegalArgumentException("Source may not be null");
    102         }
    103         this.source = partSource;
    104     }
    105 
    106     /**
    107      * FilePart Constructor.
    108      *
    109      * @param name the name for this part
    110      * @param partSource the source for this part
    111      */
    112     public FilePart(String name, PartSource partSource) {
    113         this(name, partSource, null, null);
    114     }
    115 
    116     /**
    117      * FilePart Constructor.
    118      *
    119      * @param name the name of the file part
    120      * @param file the file to post
    121      *
    122      * @throws FileNotFoundException if the <i>file</i> is not a normal
    123      * file or if it is not readable.
    124      */
    125     public FilePart(String name, File file)
    126     throws FileNotFoundException {
    127         this(name, new FilePartSource(file), null, null);
    128     }
    129 
    130     /**
    131      * FilePart Constructor.
    132      *
    133      * @param name the name of the file part
    134      * @param file the file to post
    135      * @param contentType the content type for this part, if <code>null</code> the
    136      * {@link #DEFAULT_CONTENT_TYPE default} is used
    137      * @param charset the charset encoding for this part, if <code>null</code> the
    138      * {@link #DEFAULT_CHARSET default} is used
    139      *
    140      * @throws FileNotFoundException if the <i>file</i> is not a normal
    141      * file or if it is not readable.
    142      */
    143     public FilePart(String name, File file, String contentType, String charset)
    144     throws FileNotFoundException {
    145         this(name, new FilePartSource(file), contentType, charset);
    146     }
    147 
    148      /**
    149      * FilePart Constructor.
    150      *
    151      * @param name the name of the file part
    152      * @param fileName the file name
    153      * @param file the file to post
    154      *
    155      * @throws FileNotFoundException if the <i>file</i> is not a normal
    156      * file or if it is not readable.
    157      */
    158     public FilePart(String name, String fileName, File file)
    159     throws FileNotFoundException {
    160         this(name, new FilePartSource(fileName, file), null, null);
    161     }
    162 
    163      /**
    164      * FilePart Constructor.
    165      *
    166      * @param name the name of the file part
    167      * @param fileName the file name
    168      * @param file the file to post
    169      * @param contentType the content type for this part, if <code>null</code> the
    170      * {@link #DEFAULT_CONTENT_TYPE default} is used
    171      * @param charset the charset encoding for this part, if <code>null</code> the
    172      * {@link #DEFAULT_CHARSET default} is used
    173      *
    174      * @throws FileNotFoundException if the <i>file</i> is not a normal
    175      * file or if it is not readable.
    176      */
    177     public FilePart(String name, String fileName, File file, String contentType, String charset)
    178     throws FileNotFoundException {
    179         this(name, new FilePartSource(fileName, file), contentType, charset);
    180     }
    181 
    182     /**
    183      * Write the disposition header to the output stream
    184      * @param out The output stream
    185      * @throws IOException If an IO problem occurs
    186      * @see Part#sendDispositionHeader(OutputStream)
    187      */
    188     @Override
    189     protected void sendDispositionHeader(OutputStream out)
    190     throws IOException {
    191         LOG.trace("enter sendDispositionHeader(OutputStream out)");
    192         super.sendDispositionHeader(out);
    193         String filename = this.source.getFileName();
    194         if (filename != null) {
    195             out.write(FILE_NAME_BYTES);
    196             out.write(QUOTE_BYTES);
    197             out.write(EncodingUtils.getAsciiBytes(filename));
    198             out.write(QUOTE_BYTES);
    199         }
    200     }
    201 
    202     /**
    203      * Write the data in "source" to the specified stream.
    204      * @param out The output stream.
    205      * @throws IOException if an IO problem occurs.
    206      * @see Part#sendData(OutputStream)
    207      */
    208     @Override
    209     protected void sendData(OutputStream out) throws IOException {
    210         LOG.trace("enter sendData(OutputStream out)");
    211         if (lengthOfData() == 0) {
    212 
    213             // this file contains no data, so there is nothing to send.
    214             // we don't want to create a zero length buffer as this will
    215             // cause an infinite loop when reading.
    216             LOG.debug("No data to send.");
    217             return;
    218         }
    219 
    220         byte[] tmp = new byte[4096];
    221         InputStream instream = source.createInputStream();
    222         try {
    223             int len;
    224             while ((len = instream.read(tmp)) >= 0) {
    225                 out.write(tmp, 0, len);
    226             }
    227         } finally {
    228             // we're done with the stream, close it
    229             instream.close();
    230         }
    231     }
    232 
    233     /**
    234      * Returns the source of the file part.
    235      *
    236      * @return The source.
    237      */
    238     protected PartSource getSource() {
    239         LOG.trace("enter getSource()");
    240         return this.source;
    241     }
    242 
    243     /**
    244      * Return the length of the data.
    245      * @return The length.
    246      * @see Part#lengthOfData()
    247      */
    248     @Override
    249     protected long lengthOfData() {
    250         LOG.trace("enter lengthOfData()");
    251         return source.getLength();
    252     }
    253 
    254 }
    255