1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 package org.apache.commons.httpclient.methods.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.commons.httpclient.util.EncodingUtil;
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@yahoo.com">Matthew Albright</a>
47 * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
48 * @author <a href="mailto:adrian@ephox.com">Adrian Sutton</a>
49 * @author <a href="mailto:becke@u.washington.edu">Michael Becke</a>
50 * @author <a href="mailto:mdiggory@latte.harvard.edu">Mark Diggory</a>
51 * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
52 * @author <a href="mailto:oleg@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 EncodingUtil.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 protected void sendDispositionHeader(OutputStream out)
189 throws IOException {
190 LOG.trace("enter sendDispositionHeader(OutputStream out)");
191 super.sendDispositionHeader(out);
192 String filename = this.source.getFileName();
193 if (filename != null) {
194 out.write(FILE_NAME_BYTES);
195 out.write(QUOTE_BYTES);
196 out.write(EncodingUtil.getAsciiBytes(filename));
197 out.write(QUOTE_BYTES);
198 }
199 }
200
201 /***
202 * Write the data in "source" to the specified stream.
203 * @param out The output stream.
204 * @throws IOException if an IO problem occurs.
205 * @see org.apache.commons.httpclient.methods.multipart.Part#sendData(OutputStream)
206 */
207 protected void sendData(OutputStream out) throws IOException {
208 LOG.trace("enter sendData(OutputStream out)");
209 if (lengthOfData() == 0) {
210
211
212
213
214 LOG.debug("No data to send.");
215 return;
216 }
217
218 byte[] tmp = new byte[4096];
219 InputStream instream = source.createInputStream();
220 try {
221 int len;
222 while ((len = instream.read(tmp)) >= 0) {
223 out.write(tmp, 0, len);
224 }
225 } finally {
226
227 instream.close();
228 }
229 }
230
231 /***
232 * Returns the source of the file part.
233 *
234 * @return The source.
235 */
236 protected PartSource getSource() {
237 LOG.trace("enter getSource()");
238 return this.source;
239 }
240
241 /***
242 * Return the length of the data.
243 * @return The length.
244 * @throws IOException if an IO problem occurs
245 * @see org.apache.commons.httpclient.methods.multipart.Part#lengthOfData()
246 */
247 protected long lengthOfData() throws IOException {
248 LOG.trace("enter lengthOfData()");
249 return source.getLength();
250 }
251
252 }