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