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