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