KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > struts > upload > MultipartIterator


1 /*
2  * $Id: MultipartIterator.java 54929 2004-10-16 16:38:42Z germuska $
3  *
4  * Copyright 1999-2004 The Apache Software Foundation.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */

18
19 package org.apache.struts.upload;
20
21 import java.io.BufferedOutputStream JavaDoc;
22 import java.io.ByteArrayOutputStream JavaDoc;
23 import java.io.File JavaDoc;
24 import java.io.FileOutputStream JavaDoc;
25 import java.io.IOException JavaDoc;
26 import java.io.InputStream JavaDoc;
27
28 import javax.servlet.http.HttpServletRequest JavaDoc;
29
30 /**
31  * The MultipartIterator class is responsible for reading the
32  * input data of a multipart request and splitting it up into
33  * input elements, wrapped inside of a
34  * {@link org.apache.struts.upload.MultipartElement MultipartElement}
35  * for easy definition. To use this class, create a new instance
36  * of MultipartIterator passing it a HttpServletRequest in the
37  * constructor. Then use the {@link #getNextElement() getNextElement}
38  * method until it returns null, then you're finished. Example: <br>
39  * <pre>
40  * MultipartIterator iterator = new MultipartIterator(request);
41  * MultipartElement element;
42  *
43  * while ((element = iterator.getNextElement()) != null) {
44  * //do something with element
45  * }
46  * </pre>
47  *
48  * @see org.apache.struts.upload.MultipartElement
49  *
50  * @deprecated Use the Commons FileUpload based multipart handler instead. This
51  * class will be removed after Struts 1.2.
52  */

53 public class MultipartIterator
54 {
55
56     /**
57      * The default encoding of a text element if none is specified.
58      */

59     private static final String JavaDoc DEFAULT_ENCODING = "iso-8859-1";
60
61     /**
62      * The size in bytes to copy of text data at a time.
63      */

64     private static final int TEXT_BUFFER_SIZE = 1000;
65
66     /**
67      * The name of the Content-Type header.
68      */

69     public static String JavaDoc HEADER_CONTENT_TYPE = "Content-Type";
70
71     /**
72      * The name of the Content-Disposition header.
73      */

74     public static final String JavaDoc HEADER_CONTENT_DISPOSITION = "Content-Disposition";
75
76     /**
77      * The exception message for when the boundary of a multipart request can't be determined.
78      */

79     public static final String JavaDoc MESSAGE_CANNOT_RETRIEVE_BOUNDARY =
80                                                     "MultipartIterator: cannot retrieve boundary for multipart request";
81
82     private static final String JavaDoc PARAMETER_BOUNDARY = "boundary=";
83
84     private static final String JavaDoc FILE_PREFIX = "strts";
85
86     /**
87      * The request instance for this class
88      */

89     protected HttpServletRequest JavaDoc request;
90
91     /**
92      * The InputStream to use to read the multipart data.
93      */

94     protected MultipartBoundaryInputStream inputStream;
95
96     /**
97      * The boundary for this multipart request
98      */

99     protected String JavaDoc boundary;
100
101     /**
102      * The maximum file size in bytes allowed. Ignored if -1
103      */

104     protected long maxSize = -1;
105
106     /**
107      * The content length of this request
108      */

109     protected int contentLength;
110
111     /**
112      * The size in bytes written to the filesystem at a time [20K]
113      */

114     protected int diskBufferSize = 2 * 10240;
115
116     /**
117      * The amount of data read from a request at a time.
118      * This also represents the maximum size in bytes of
119      * a line read from the request [4KB]
120      */

121     protected int bufferSize = 4096;
122
123     /**
124      * The temporary directory to store files
125      */

126     protected String JavaDoc tempDir;
127
128     /**
129      * The content-type.
130      */

131     protected String JavaDoc contentType;
132
133     /**
134      * Whether the maximum length has been exceeded.
135      */

136     protected boolean maxLengthExceeded;
137
138     /**
139      * Constructs a MultipartIterator with a default buffer size and no file size
140      * limit
141      *
142      * @param request The multipart request to iterate
143      */

144     public MultipartIterator(HttpServletRequest JavaDoc request) throws IOException JavaDoc
145     {
146         this(request, -1);
147     }
148
149     /**
150      * Constructs a MultipartIterator with the specified buffer size and
151      * no file size limit
152      *
153      * @param request The multipart request to iterate
154      * @param bufferSize The size in bytes that should be read from the input
155      * stream at a times
156      */

157     public MultipartIterator(HttpServletRequest JavaDoc request, int bufferSize) throws IOException JavaDoc
158     {
159         this (request, bufferSize, -1);
160     }
161
162     /**
163      * Constructs a MultipartIterator with the specified buffer size and
164      * the specified file size limit in bytes
165      *
166      * @param request The multipart request to iterate
167      * @param bufferSize The size in bytes that should be read from the input
168      * stream at a times
169      * @param maxSize The maximum size in bytes allowed for a multipart element's data
170      */

171     public MultipartIterator(HttpServletRequest JavaDoc request, int bufferSize, long maxSize) throws IOException JavaDoc
172     {
173         this(request, bufferSize, maxSize, null);
174     }
175
176     public MultipartIterator(HttpServletRequest JavaDoc request, int bufferSize, long maxSize, String JavaDoc tempDir) throws IOException JavaDoc
177     {
178         this.request = request;
179         this.maxSize = maxSize;
180         if (bufferSize > -1)
181         {
182             this.bufferSize = bufferSize;
183         }
184         if (tempDir != null)
185         {
186             this.tempDir = tempDir;
187         }
188         else
189         {
190             //default to system-wide tempdir
191
this.tempDir = System.getProperty("java.io.tmpdir");
192         }
193         this.maxLengthExceeded = false;
194         this.inputStream = new MultipartBoundaryInputStream();
195         parseRequest();
196     }
197
198     /**
199      * Handles retrieving the boundary and setting the input stream
200      */

201     protected void parseRequest() throws IOException JavaDoc
202     {
203         //get the content-type header, which contains the boundary used for separating multipart elements
204
getContentTypeOfRequest();
205         //get the content-length header, used to prevent denial of service attacks and for detecting
206
//whether a file size is over the limit before the client sends the file
207
this.contentLength = this.request.getContentLength();
208         //parse the boundary from the content-type header's value
209
getBoundaryFromContentType();
210         //don't let the stream read past the content length
211
this.inputStream.setMaxLength(this.contentLength+1);
212         //just stop now if the content length is bigger than the maximum allowed size
213
if ((this.maxSize > -1) && (this.contentLength > this.maxSize))
214         {
215             this.maxLengthExceeded = true;
216         }
217         else
218         {
219             InputStream JavaDoc requestInputStream = this.request.getInputStream();
220             //mark the input stream to allow multiple reads
221
if (requestInputStream.markSupported())
222             {
223                 requestInputStream.mark(contentLength+1);
224             }
225             this.inputStream.setBoundary(this.boundary);
226             this.inputStream.setInputStream(requestInputStream);
227         }
228     }
229
230     /**
231      * Retrieves the next element in the iterator if one exists.
232      *
233      * @throws IOException if the post size exceeds the maximum file size
234      * passed in the 3 argument constructor or if the "ISO-8859-1" encoding isn't found
235      * @return a {@link org.apache.struts.upload.MultipartElement MultipartElement}
236      * representing the next element in the request data
237      *
238      */

239     public MultipartElement getNextElement() throws IOException JavaDoc
240     {
241         //the MultipartElement to return
242
MultipartElement element = null;
243         if (!isMaxLengthExceeded())
244         {
245             if (!this.inputStream.isFinalBoundaryEncountered())
246             {
247                 if (this.inputStream.isElementFile())
248                 {
249                     //attempt to create the multipart element from the collected data
250
element = createFileMultipartElement();
251                 }
252                 //process a text element
253
else
254                 {
255                     String JavaDoc encoding = getElementEncoding();
256                     element = createTextMultipartElement(encoding);
257                 }
258                 this.inputStream.resetForNextBoundary();
259             }
260         }
261         return element;
262     }
263
264     /**
265      * Get the character encoding used for this current multipart element.
266      */

267     protected String JavaDoc getElementEncoding()
268     {
269         String JavaDoc encoding = this.inputStream.getElementCharset();
270         if (encoding == null)
271         {
272             encoding = this.request.getCharacterEncoding();
273             if (encoding == null)
274             {
275                 encoding = DEFAULT_ENCODING;
276             }
277         }
278         return encoding;
279     }
280
281     /**
282      * Create a text element from the data in the body of the element.
283      * @param encoding The character encoding of the string.
284      */

285     protected MultipartElement createTextMultipartElement(String JavaDoc encoding) throws IOException JavaDoc
286     {
287         MultipartElement element;
288
289         int read = 0;
290         byte[] buffer = new byte[TEXT_BUFFER_SIZE];
291         ByteArrayOutputStream JavaDoc baos = new ByteArrayOutputStream JavaDoc();
292         while ((read = this.inputStream.read(buffer, 0, TEXT_BUFFER_SIZE)) > 0)
293         {
294             baos.write(buffer, 0, read);
295         }
296         //create the element
297
String JavaDoc value = baos.toString(encoding);
298         element = new MultipartElement(this.inputStream.getElementName(), value);
299         return element;
300     }
301
302     /**
303      * Create a multipart element instance representing the file in the stream.
304      */

305     protected MultipartElement createFileMultipartElement() throws IOException JavaDoc
306     {
307         MultipartElement element;
308         //create a local file on disk representing the element
309
File JavaDoc elementFile = createLocalFile();
310         element = new MultipartElement(this.inputStream.getElementName(), this.inputStream.getElementFileName(),
311                                        this.inputStream.getElementContentType(), elementFile);
312         return element;
313     }
314
315     /**
316      * Set the maximum amount of bytes read from a line at one time
317      *
318      * @see javax.servlet.ServletInputStream#readLine(byte[], int, int)
319      */

320     public void setBufferSize(int bufferSize) {
321         this.bufferSize = bufferSize;
322     }
323
324     /**
325      * Get the maximum amount of bytes read from a line at one time
326      *
327      * @see javax.servlet.ServletInputStream#readLine(byte[], int, int)
328      */

329     public int getBufferSize() {
330         return bufferSize;
331     }
332
333     /**
334      * Set the maximum post data size allowed for a multipart request
335      * @param maxSize The maximum post data size in bytes, set to <code>-1</code>
336      * for no limit
337      */

338     public void setMaxSize(long maxSize) {
339         this.maxSize = maxSize;
340     }
341
342     /**
343      * Get the maximum post data size allowed for a multipart request
344      * @return The maximum post data size in bytes
345      */

346     public long getMaxSize()
347     {
348         return this.maxSize;
349     }
350
351     /**
352      * Whether or not the maximum length has been exceeded by the client.
353      */

354     public boolean isMaxLengthExceeded()
355     {
356         return (this.maxLengthExceeded || this.inputStream.isMaxLengthMet());
357     }
358
359
360     /**
361      * Parses a content-type String for the boundary.
362      */

363     private final void getBoundaryFromContentType() throws IOException JavaDoc
364     {
365         if (this.contentType.lastIndexOf(PARAMETER_BOUNDARY) != -1)
366         {
367             String JavaDoc _boundary = this.contentType.substring(this.contentType.lastIndexOf(PARAMETER_BOUNDARY) + 9);
368             if (_boundary.endsWith("\n"))
369             {
370                 //strip it off
371
this.boundary = _boundary.substring(0, _boundary.length()-1);
372             }
373             this.boundary = _boundary;
374         }
375         else
376         {
377             this.boundary = null;
378         }
379         //throw an exception if we're unable to obtain a boundary at this point
380
if ((this.boundary == null) || (this.boundary.length() < 1))
381         {
382             throw new IOException JavaDoc(MESSAGE_CANNOT_RETRIEVE_BOUNDARY);
383         }
384     }
385     /**
386      * Gets the value of the Content-Type header of the request.
387      */

388     private final void getContentTypeOfRequest()
389     {
390         this.contentType = request.getContentType();
391         if (this.contentType == null)
392         {
393             this.contentType = this.request.getHeader(HEADER_CONTENT_TYPE);
394         }
395     }
396
397     /**
398      * Creates a file on disk from the current mulitpart element.
399      */

400     protected File JavaDoc createLocalFile() throws IOException JavaDoc
401     {
402         File JavaDoc tempFile = File.createTempFile(FILE_PREFIX, null, new File JavaDoc(this.tempDir));
403         BufferedOutputStream JavaDoc fos = new BufferedOutputStream JavaDoc(new FileOutputStream JavaDoc(tempFile), this.diskBufferSize);
404         int read = 0;
405         byte buffer[] = new byte[this.diskBufferSize];
406         while ((read = this.inputStream.read(buffer, 0, this.diskBufferSize)) > 0)
407         {
408             fos.write(buffer, 0, read);
409         }
410         fos.flush();
411         fos.close();
412         return tempFile;
413     }
414 }
415
Popular Tags