KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > enterprise > tools > admingui > servlet > MultipartHandler


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23
24 package com.sun.enterprise.tools.admingui.servlet;
25 /*
26  * MultipartHandler:
27  * A utility class to handle content of multipart/form-data type used in form uploads.
28  *
29  * Parses and provides accessor functions to extract the form fields and the uploaded
30  * file content parts separated by a boundary string.
31  * See http://www.ietf.org/rfc/rfc1867.txt.
32  */

33
34 import java.io.BufferedOutputStream JavaDoc;
35 import java.io.ByteArrayOutputStream JavaDoc;
36 import java.io.File JavaDoc;
37 import java.io.FileOutputStream JavaDoc;
38 import java.io.FilterInputStream JavaDoc;
39 import java.io.IOException JavaDoc;
40 import java.io.InputStream JavaDoc;
41 import java.io.OutputStream JavaDoc;
42 import java.util.Enumeration JavaDoc;
43 import java.util.Hashtable JavaDoc;
44 import java.util.HashMap JavaDoc;
45 import java.util.Vector JavaDoc;
46
47 import javax.servlet.ServletInputStream JavaDoc;
48 import javax.servlet.http.HttpServletRequest JavaDoc;
49
50 //i18n import
51
//import com.iplanet.ias.util.i18n.StringManager;
52

53 public class MultipartHandler {
54
55   private static final int DEFAULT_MAX_UPLOAD_SIZE = 1024 * 1024; // 1Mb
56

57   protected Hashtable JavaDoc formFields = new Hashtable JavaDoc(); // field name - Vector of values
58
protected Hashtable JavaDoc uploadFiles = new Hashtable JavaDoc(); // file name - MultipartFile
59

60   /** servlet request */
61   private HttpServletRequest JavaDoc req;
62
63   /** input stream to read parts from */
64   private ServletInputStream JavaDoc in;
65   
66   /** MIME boundary that delimits parts */
67   private String JavaDoc boundary;
68   
69   /** buffer for readLine method */
70   private byte[] buf = new byte[8 * 1024];
71   
72   /** upload directory */
73   private File JavaDoc uploadDir;
74
75   /** encoding used for the from fields */
76   private String JavaDoc fieldEncoding = "ISO-8859-1";
77
78   // i18n StringManager
79
/*private static StringManager localStrings =
80     StringManager.getManager( MultipartHandler.class );*/

81
82   /**
83    * Instantiate a new multipart handler with default
84    */

85   public MultipartHandler(HttpServletRequest JavaDoc request,
86                           String JavaDoc tmpDirectory) throws IOException JavaDoc {
87     this(request, tmpDirectory, DEFAULT_MAX_UPLOAD_SIZE, "ISO-8859-1");
88   }
89
90   public MultipartHandler(HttpServletRequest JavaDoc request,
91                           String JavaDoc tmpDirectory,
92                           int maxUploadSize) throws IOException JavaDoc {
93     this(request, tmpDirectory, maxUploadSize, "ISO-8859-1");
94   }
95
96   /**
97    * Instantiate a new MultipartHandler to handle the given request,
98    * saving any uploaded files to the given directory and limiting the
99    * upload size to maxUploadSize.
100    *
101    * An IOException is thrown when the request content-type doesn't match
102    * with multipart/form-data or if the upload size exceeds the given limit.
103    *
104    * call parseMultipartUpload() to parse various parts of the posted data and then
105    * call getParameter(), getParameters(), getParameterNames() and getParameterValues()
106    * functions to access form field names and their values.
107    * call getFile(), getFileType() to access uploaded file and its content-type.
108    */

109   public MultipartHandler(HttpServletRequest JavaDoc request,
110                           String JavaDoc tmpDirectory,
111                           int maxUploadSize,
112                           String JavaDoc fieldEncoding) throws IOException JavaDoc {
113
114     // Ensure we are passed legal arguments
115
if (request == null) {
116       //String msg = localStrings.getString( "admin.server.gui.servlet.request_cannot_be_null" );
117
throw new IllegalArgumentException JavaDoc( "request is null" );
118     }
119     if (tmpDirectory == null) {
120       //String msg = localStrings.getString( "admin.server.gui.servlet.tmpdirectory_cannot_be_null" );
121
throw new IllegalArgumentException JavaDoc( "tmp Dir is null" );
122     }
123     if (maxUploadSize <= 0) {
124         //String msg = localStrings.getString( "admin.server.gui.servlet.maxpostsize_must_be_positive" );
125
throw new IllegalArgumentException JavaDoc( "Max size is < 0" );
126     }
127
128     // Ensure that the directory exists and is writable (this should be a temp directory)
129
uploadDir = new File JavaDoc(tmpDirectory);
130     if (!uploadDir.isDirectory()) {
131       //String msg = localStrings.getString( "admin.server.gui.servlet.not_directory", tmpDirectory );
132
throw new IllegalArgumentException JavaDoc( "Not a Directory" );
133     }
134     if (!uploadDir.canWrite()) {
135       //String msg = localStrings.getString( "admin.server.gui.servlet.not_writable", tmpDirectory );
136
throw new IllegalArgumentException JavaDoc("write protected" );
137     }
138     int length = request.getContentLength();
139     //commented this code to remove the restriction on the file upload size.
140
/*if (length > maxUploadSize) {
141       //String msg = localStrings.getString( "admin.server.gui.servlet.posted_content_length_exceeds_limit", new Integer(length), new Integer(maxUploadSize) );
142       throw new IOException( msg );
143     }*/

144     // Check the content type to make sure it's "multipart/form-data"
145
String JavaDoc type = request.getContentType();
146     if (type == null ||
147         !type.toLowerCase().startsWith("multipart/form-data")) {
148       //String msg = localStrings.getString( "admin.server.gui.servlet.posted_content_type_not_multipart" );
149
throw new IOException JavaDoc( "type null" );
150     }
151
152     // Check the content length to prevent denial of service attacks
153
this.fieldEncoding = fieldEncoding;
154     this.req = request;
155   }
156
157   /* parseMultipartUpload:
158    *
159    * This function parses the multipart/form-data and throws an IOException
160    * if there's any problem reading or parsing the request or if the posted
161    * content is larger than the maximum permissible size.
162    */

163   public void parseMultipartUpload()
164                 throws IOException JavaDoc {
165     // setup the initial buffered input stream, boundary string that separates
166
// various parts in the stream.
167
startMultipartParse();
168
169     HashMap JavaDoc partHeaders = parsePartHeaders();
170     while (partHeaders != null) {
171
172         String JavaDoc fieldName = (String JavaDoc)partHeaders.get("fieldName");
173         String JavaDoc fileName = (String JavaDoc)partHeaders.get("fileName");
174
175         if (fileName != null) {
176             // This is a file upload part
177
if (fileName.equals("")) {
178                 fileName = null; // empty filename, probably an "empty" file param
179
}
180
181             if (fileName != null) {
182                 // a filename was actually specified
183
saveUploadFile( fileName );
184
185                 uploadFiles.put(fieldName,
186                                 new MultipartFile(
187                                        uploadDir.toString(),
188                                        fileName,
189                                        (String JavaDoc)partHeaders.get("content-type"))
190                                );
191             }
192             else {
193         // FIXME: This does not call saveUploadFile(name);
194
uploadFiles.put(fieldName, new MultipartFile(null, null, null));
195             }
196         }
197         else {
198             // this is a parameters list part
199
byte[] valueBytes = parseFormFieldBytes();
200             String JavaDoc value = new String JavaDoc(valueBytes, fieldEncoding);
201
202             Vector JavaDoc existingValues = (Vector JavaDoc)formFields.get(fieldName);
203             if (existingValues == null) {
204                 existingValues = new Vector JavaDoc();
205                 formFields.put(fieldName, existingValues);
206             }
207             existingValues.addElement(value);
208         }
209
210         partHeaders.clear();
211         partHeaders = parsePartHeaders();
212     }
213   }
214
215   private void startMultipartParse()
216                 throws IOException JavaDoc {
217     // Get the boundary string; it's included in the content type.
218
// Should look something like "------------------------12012133613061"
219
String JavaDoc boundary = parseBoundary(req.getContentType());
220     if (boundary == null) {
221       //String msg = localStrings.getString( "admin.server.gui.servlet.separation_boundary_not_specified" );
222
throw new IOException JavaDoc( "boundary is nul" );
223     }
224
225     this.in = req.getInputStream();
226     this.boundary = boundary;
227     
228     // Read the first line, should be the first boundary
229
String JavaDoc line = readLine();
230     if (line == null) {
231       //String msg = localStrings.getString( "admin.server.gui.servlet.corrupt_form_data_premature_ending" );
232
throw new IOException JavaDoc( "line is null" );
233     }
234
235     // Verify that the line is the boundary
236
if (!line.startsWith(boundary)) {
237       //String msg = localStrings.getString( "admin.server.gui.servlet.corrupt_form_data_no_leading_boundary", line, boundary );
238
throw new IOException JavaDoc( "not start with boundary" );
239     }
240   }
241
242   /**
243    * parse the headers of the individual part; they look like this:
244    * Content-Disposition: form-data; name="field1"; filename="file1.txt"
245    * Content-Type: type/subtype
246    * Content-Transfer-Encoding: binary
247    */

248   private HashMap JavaDoc parsePartHeaders() throws IOException JavaDoc {
249     HashMap JavaDoc partHeaders = new HashMap JavaDoc();
250
251     Vector JavaDoc headers = new Vector JavaDoc();
252     String JavaDoc line = readLine();
253     if (line == null) {
254       // No parts left, we're done
255
return null;
256     }
257     else if (line.length() == 0) {
258       // IE4 on Mac sends an empty line at the end; treat that as the end.
259
return null;
260     }
261     headers.addElement(line);
262
263     // Read the following header lines we hit an empty line
264
while ((line = readLine()) != null && (line.length() > 0)) {
265       headers.addElement(line);
266     }
267
268     // If we got a null above, it's the end
269
if (line == null) {
270       return null;
271     }
272
273     // default part content type (rfc1867)
274
partHeaders.put("content-type", "text/plain");
275
276     Enumeration JavaDoc ee = headers.elements();
277     while (ee.hasMoreElements()) {
278       String JavaDoc headerline = (String JavaDoc) ee.nextElement();
279
280       if (headerline.toLowerCase().startsWith("content-disposition:")) {
281         // Parse the content-disposition line
282
parseContentDisposition(headerline, partHeaders);
283       }
284       else if (headerline.toLowerCase().startsWith("content-type:")) {
285         // Get the content type, or null if none specified
286
parseContentType(headerline, partHeaders);
287       }
288     }
289
290     return partHeaders;
291   }
292
293   /**
294    * parses and returns the boundary token from a line.
295    */

296   private String JavaDoc parseBoundary(String JavaDoc line) {
297     // Use lastIndexOf() because IE 4.01 on Win98 has been known to send the
298
// "boundary=" string multiple times.
299
int index = line.lastIndexOf("boundary=");
300     if (index == -1) {
301       return null;
302     }
303     String JavaDoc boundary = line.substring(index + 9); // 9 for "boundary="
304
if (boundary.charAt(0) == '"') {
305       // The boundary is enclosed in quotes, strip them
306
index = boundary.lastIndexOf('"');
307       boundary = boundary.substring(1, index);
308     }
309
310     // The real boundary is always preceeded by an extra "--"
311
boundary = "--" + boundary;
312
313     return boundary;
314   }
315
316   /**
317    * parses and returns content-disposition header and stores the values
318    * in the partHeaders.
319    *
320    * throws IOException if the line is malformatted.
321    */

322   private void parseContentDisposition(String JavaDoc line, HashMap JavaDoc partHeaders)
323                     throws IOException JavaDoc {
324
325     // Convert the line to a lowercase string without the ending \r\n
326
// Keep the original line for error messages and for variable names.
327
String JavaDoc origline = line;
328     line = origline.toLowerCase();
329
330     // Get the content disposition, should be "form-data"
331
int start = line.indexOf("content-disposition: ");
332     int end = line.indexOf(";");
333     if (start == -1 || end == -1) {
334       //String msg = localStrings.getString( "admin.server.gui.servlet.content_disposition_corrupt", origline );
335
throw new IOException JavaDoc( "end reached" );
336     }
337     String JavaDoc disposition = line.substring(start + 21, end);
338     if (!disposition.equals("form-data")) {
339       //String msg = localStrings.getString( "admin.server.gui.servlet.invalid_content_disposition", disposition );
340
throw new IOException JavaDoc( "fome-data not match" );
341     }
342
343     // Get the field name
344
start = line.indexOf("name=\"", end); // start at last semicolon
345
end = line.indexOf("\"", start + 7); // skip name=\"
346
if (start == -1 || end == -1) {
347       //String msg = localStrings.getString( "admin.server.gui.servlet.content_disposition_corrupt", origline );
348
throw new IOException JavaDoc( "data corrupt" );
349     }
350
351     String JavaDoc name = origline.substring(start + 6, end);
352
353     // Get the fileName, if given
354
String JavaDoc fileName = null;
355     String JavaDoc origFileName = null;
356     start = line.indexOf("filename=\"", end + 2); // start after name
357
end = line.indexOf("\"", start + 10); // skip filename=\"
358

359     if (start != -1 && end != -1) { // note the !=
360
fileName = origline.substring(start + 10, end);
361       origFileName = fileName;
362       // The filename may contain a full path. Cut to just the filename.
363
int slash =
364         Math.max(fileName.lastIndexOf('/'), fileName.lastIndexOf('\\'));
365       if (slash > -1) {
366         fileName = fileName.substring(slash + 1); // past last slash
367
}
368     }
369
370     // fill in the part parameters map: disposition, name, filename
371
// empty fileName denotes no file posted!
372
partHeaders.put("disposition", disposition);
373     partHeaders.put("fieldName", name);
374     partHeaders.put("fileName", fileName);
375     partHeaders.put("filePath", origFileName);
376   }
377
378   /**
379    * parse and returns the content type from a line, or null if the
380    * line was empty.
381    */

382   private void parseContentType(String JavaDoc line, HashMap JavaDoc partHeaders)
383                 throws IOException JavaDoc {
384     String JavaDoc contentType = null;
385
386     // Convert the line to a lowercase string
387
String JavaDoc origline = line;
388     line = origline.toLowerCase();
389
390     // Get the content type, if any
391
if (line.startsWith("content-type")) {
392       int start = line.indexOf(" ");
393
394       if (start == -1) {
395         //String msg = localStrings.getString( "admin.server.gui.servlet.corrupt_content_type", origline );
396
throw new IOException JavaDoc( "no start" );
397       }
398       contentType = line.substring(start + 1);
399       
400       partHeaders.put("content-type", contentType);
401     }
402     else if (line.length() != 0) { // no content type, so should be empty
403
//String msg = localStrings.getString( "admin.server.gui.servlet.malformed_line_after_disposition", origline );
404
throw new IOException JavaDoc( "length 0" );
405     }
406   }
407
408  /** parse contents of a form field parameter; uses the encoding set by the user
409   */

410  private byte[] parseFormFieldBytes() throws IOException JavaDoc {
411
412     // Copy the part's contents into a byte array
413
MultipartInputStream pis = new MultipartInputStream(in, boundary);
414
415     ByteArrayOutputStream JavaDoc baos = new ByteArrayOutputStream JavaDoc(512);
416     byte[] buf = new byte[128];
417     int read;
418     while ((read = pis.read(buf)) != -1) {
419       baos.write(buf, 0, read);
420     }
421     pis.close();
422     baos.close();
423     
424     // get the value bytes
425
return baos.toByteArray();
426   }
427
428   /**
429    * Read the next line of input.
430    *
431    * @return a String containing the next line of input from the stream,
432    * or null to indicate the end of the stream.
433    * @exception IOException if an input or output exception has occurred.
434    */

435   private String JavaDoc readLine() throws IOException JavaDoc {
436     StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc();
437     int result;
438     String JavaDoc line;
439
440     do {
441       result = in.readLine(buf, 0, buf.length); // does +=
442
if (result != -1) {
443         sbuf.append(new String JavaDoc(buf, 0, result, "ISO-8859-1"));
444       }
445     } while (result == buf.length); // loop only if the buffer was filled
446

447     if (sbuf.length() == 0) {
448       return null; // nothing read, must be at the end of stream
449
}
450
451     // Cut off the trailing \n or \r\n
452
// It should always be \r\n but IE5 sometimes does just \n
453
int len = sbuf.length();
454     if (sbuf.charAt(len - 2) == '\r') {
455       sbuf.setLength(len - 2); // cut \r\n
456
}
457     else {
458       sbuf.setLength(len - 1); // cut \n
459
}
460     return sbuf.toString();
461   }
462
463   /**
464    * Write this file part to the specified directory.
465    */

466   private long saveUploadFile(String JavaDoc fileName)
467                 throws IOException JavaDoc {
468
469     long written = 0;
470     OutputStream JavaDoc fileOut = null;
471
472     try {
473       // Only do something if this part contains a file
474
File JavaDoc file = new File JavaDoc(uploadDir, fileName);
475
476       fileOut = new BufferedOutputStream JavaDoc(new FileOutputStream JavaDoc(file));
477       int numBytes;
478       byte[] buf = new byte[8 * 1024];
479
480       /** input stream containing file data */
481       MultipartInputStream partInput = new MultipartInputStream(in, boundary);
482
483       while((numBytes = partInput.read(buf)) != -1) {
484         fileOut.write(buf, 0, numBytes);
485         written += numBytes;
486       }
487
488       partInput.close();
489     }
490     finally {
491       if (fileOut != null) fileOut.close();
492     }
493
494     return written;
495   }
496
497
498   /**
499    * Returns the names of all the parameters as an Enumeration of
500    * Strings. It returns an empty Enumeration if there are no parameters.
501    *
502    */

503   public Enumeration JavaDoc getParameterNames() {
504     return formFields.keys();
505   }
506
507   /**
508    * Returns the names of all the uploaded files as an Enumeration of
509    * Strings. It returns an empty Enumeration if there are no uploaded
510    * files. Each file name is the name specified by the form, not by
511    * the user.
512    *
513    */

514   public Enumeration JavaDoc getFileNames() {
515     return uploadFiles.keys();
516   }
517
518   /**
519    * Returns the value of the named parameter as a String, or null if
520    * the parameter was not sent or was sent without a value. The value
521    * is guaranteed to be in its normal, decoded form. If the parameter
522    * has multiple values, only the last one is returned (for backward
523    * compatibility). For parameters with multiple values, it's possible
524    * the last "value" may be null.
525    *
526    */

527   public String JavaDoc getParameter(String JavaDoc name) {
528     try {
529       Vector JavaDoc values = (Vector JavaDoc)formFields.get(name);
530       if (values == null || values.size() == 0) {
531         return null;
532       }
533       String JavaDoc value = (String JavaDoc)values.elementAt(values.size() - 1);
534       return value;
535     }
536     catch (Exception JavaDoc e) {
537       return null;
538     }
539   }
540
541   /**
542    * Returns the values of the named parameter as a String array, or null if
543    * the parameter was not sent. The array has one entry for each parameter
544    * field sent. If any field was sent without a value that entry is stored
545    * in the array as a null. The values are guaranteed to be in their
546    * normal, decoded form. A single value is returned as a one-element array.
547    *
548    */

549   public String JavaDoc[] getParameterValues(String JavaDoc name) {
550     try {
551       Vector JavaDoc values = (Vector JavaDoc)formFields.get(name);
552       if (values == null || values.size() == 0) {
553         return null;
554       }
555       String JavaDoc[] valuesArray = new String JavaDoc[values.size()];
556       values.copyInto(valuesArray);
557       return valuesArray;
558     }
559     catch (Exception JavaDoc e) {
560       return null;
561     }
562   }
563
564   /**
565    * Returns the filesystem name of the specified file, or null if the
566    * file was not included in the upload. A filesystem name is the name
567    * specified by the user. It is also the name under which the file is
568    * actually saved.
569    *
570    */

571   public String JavaDoc getFileName(String JavaDoc name) {
572     try {
573       MultipartFile file = (MultipartFile)uploadFiles.get(name);
574       return file.getFileName(); // may be null
575
}
576     catch (Exception JavaDoc e) {
577       return null;
578     }
579   }
580
581   /**
582    * Returns the content type of the specified file (as supplied by the
583    * client browser), or null if the file was not included in the upload.
584    *
585    */

586   public String JavaDoc getFileType(String JavaDoc name) {
587     try {
588       MultipartFile file = (MultipartFile)uploadFiles.get(name);
589       return file.getFileType(); // may be null
590
}
591     catch (Exception JavaDoc e) {
592       return null;
593     }
594   }
595
596   /**
597    * Returns a File object for the specified file saved on the server's
598    * filesystem, or null if the file was not included in the upload.
599    *
600    */

601   public File JavaDoc getFile(String JavaDoc name) {
602     try {
603       MultipartFile file = (MultipartFile)uploadFiles.get(name);
604       return file.getFile(); // may be null
605
}
606     catch (Exception JavaDoc e) {
607       return null;
608     }
609   }
610
611   /**
612    * close the multi-part form handler
613    */

614   public void close() throws IOException JavaDoc {
615     req = null;
616     in = null;
617     boundary = null;
618     buf = null;
619     uploadDir = null;
620   }
621 }
622
623 /*
624  * providing access to a single MIME part contained with in which ends with
625  * the boundary specified. It uses buffering to provide maximum performance.
626  *
627  */

628 class MultipartInputStream extends FilterInputStream JavaDoc {
629   /** boundary which "ends" the stream */
630   private String JavaDoc boundary;
631   
632   /** our buffer */
633   private byte [] buf = new byte[64*1024]; // 64k
634

635   /** number of bytes we've read into the buffer */
636   private int count;
637   
638   /** current position in the buffer */
639   private int pos;
640   
641   /** flag that indicates if we have encountered the boundary */
642   private boolean eof;
643
644   // i18n StringManager
645
/*private static StringManager localStrings =
646     StringManager.getManager( MultipartInputStream.class );*/

647     
648   /**
649    * Instantiate a MultipartInputStream which stops at the specified
650    * boundary from an underlying ServletInputStream.
651    *
652    */

653   MultipartInputStream(ServletInputStream JavaDoc in,
654                   String JavaDoc boundary) throws IOException JavaDoc {
655     super(in);
656     this.boundary = boundary;
657   }
658
659   /**
660    * Fill up our buffer from the underlying input stream, and check for the
661    * boundary that signifies end-of-file. Users of this method must ensure
662    * that they leave exactly 2 characters in the buffer before calling this
663    * method (except the first time), so that we may only use these characters
664    * if a boundary is not found in the first line read.
665    *
666    * @exception IOException if an I/O error occurs.
667    */

668   private void fill() throws IOException JavaDoc
669   {
670     if (eof)
671       return;
672     
673     // as long as we are not just starting up
674
if (count > 0)
675     {
676       // if the caller left the requisite amount spare in the buffer
677
if (count - pos == 2) {
678         // copy it back to the start of the buffer
679
System.arraycopy(buf, pos, buf, 0, count - pos);
680         count -= pos;
681         pos = 0;
682       } else {
683         // should never happen, but just in case
684
//String msg = localStrings.getString( "admin.server.gui.servlet.fill_detected_illegal_buffer_state" );
685
throw new IllegalStateException JavaDoc( "should never happen" );
686       }
687     }
688     
689     // try and fill the entire buffer, starting at count, line by line
690
// but never read so close to the end that we might split a boundary
691
int read = 0;
692     int maxRead = buf.length - boundary.length();
693     while (count < maxRead) {
694       // read a line
695
read = ((ServletInputStream JavaDoc)in).readLine(buf, count, buf.length - count);
696       // check for eof and boundary
697
if (read == -1) {
698         //String msg = localStrings.getString( "admin.server.gui.servlet.unexpected_end_part" );
699
throw new IOException JavaDoc( "read is -1" );
700       } else {
701         if (read >= boundary.length()) {
702           eof = true;
703           for (int i=0; i < boundary.length(); i++) {
704             if (boundary.charAt(i) != buf[count + i]) {
705               // Not the boundary!
706
eof = false;
707               break;
708             }
709           }
710           if (eof) {
711             break;
712           }
713         }
714       }
715       // success
716
count += read;
717     }
718   }
719   
720   /**
721    * See the general contract of the read method of InputStream.
722    * Returns -1 (end of file) when the MIME boundary of this part is encountered.
723    *
724    * throws IOException if an I/O error occurs.
725    */

726   public int read() throws IOException JavaDoc {
727     if (count - pos <= 2) {
728       fill();
729       if (count - pos <= 2) {
730         return -1;
731       }
732     }
733     return buf[pos++] & 0xff;
734   }
735
736   /**
737    * See the general contract of the read method of InputStream.
738    *
739    * Returns -1 (end of file) when the MIME boundary of this part
740    * is encountered.
741    *
742    * throws IOException if an I/O error occurs.
743    */

744   public int read(byte b[]) throws IOException JavaDoc {
745     return read(b, 0, b.length);
746   }
747
748   /**
749    * See the general contract of the read method of InputStream.
750    *
751    * Returns -1 (end of file) when the MIME boundary of this part is encountered.
752    *
753    * throws IOException if an I/O error occurs.
754    */

755   public int read(byte b[], int off, int len) throws IOException JavaDoc
756   {
757     int total = 0;
758     if (len == 0) {
759       return 0;
760     }
761
762     int avail = count - pos - 2;
763     if (avail <= 0) {
764       fill();
765       avail = count - pos - 2;
766       if(avail <= 0) {
767         return -1;
768       }
769     }
770     int copy = Math.min(len, avail);
771     System.arraycopy(buf, pos, b, off, copy);
772     pos += copy;
773     total += copy;
774       
775     while (total < len) {
776       fill();
777       avail = count - pos - 2;
778       if(avail <= 0) {
779         return total;
780       }
781       copy = Math.min(len - total, avail);
782       System.arraycopy(buf, pos, b, off + total, copy);
783       pos += copy;
784       total += copy;
785     }
786     return total;
787   }
788
789   /**
790    * Returns the number of bytes that can be read from this input stream
791    * without blocking. This is a standard InputStream idiom
792    * to deal with buffering gracefully, and is not same as the length of the
793    * part arriving in this stream.
794    *
795    * throws IOException if an I/O error occurs.
796    */

797   public int available() throws IOException JavaDoc {
798     int avail = (count - pos - 2) + in.available();
799     // Never return a negative value
800
return (avail < 0 ? 0 : avail);
801   }
802
803   /**
804    * Closes this input stream and releases any system resources
805    * associated with the stream. This method will read any unread data
806    * in the MIME part so that the next part starts an an expected place in
807    * the parent InputStream.
808    *
809    * throws IOException if an I/O error occurs.
810    */

811   public void close() throws IOException JavaDoc {
812     if (!eof) {
813       while (read(buf, 0, buf.length) != -1)
814         ; // do nothing
815
}
816   }
817 }
818
819 /** A class to hold information about an uploaded file. */
820 class MultipartFile {
821
822   private String JavaDoc dir;
823   private String JavaDoc filename;
824   private String JavaDoc type;
825
826   MultipartFile(String JavaDoc dir, String JavaDoc filename, String JavaDoc type) {
827     this.dir = dir;
828     this.filename = filename;
829     this.type = type;
830   }
831
832   public String JavaDoc getFileType() {
833     return type;
834   }
835
836   public String JavaDoc getFileName() {
837     return filename;
838   }
839
840   public File JavaDoc getFile() {
841     if (dir == null || filename == null) {
842       return null;
843     }
844     else {
845       return new File JavaDoc(dir + File.separator + filename);
846     }
847   }
848 }
849
Popular Tags