FileUploadBase.java

00001 /*
00002  * $Header: /home/cvs/jakarta-commons/fileupload/src/java/org/apache/commons/fileupload/FileUploadBase.java,v 1.3 2003/06/01 00:18:13 martinc Exp $
00003  * $Revision: 1.3 $
00004  * $Date: 2003/06/01 00:18:13 $
00005  *
00006  * ====================================================================
00007  *
00008  * The Apache Software License, Version 1.1
00009  *
00010  * Copyright (c) 2001-2003 The Apache Software Foundation.  All rights
00011  * reserved.
00012  *
00013  * Redistribution and use in source and binary forms, with or without
00014  * modification, are permitted provided that the following conditions
00015  * are met:
00016  *
00017  * 1. Redistributions of source code must retain the above copyright
00018  *    notice, this list of conditions and the following disclaimer.
00019  *
00020  * 2. Redistributions in binary form must reproduce the above copyright
00021  *    notice, this list of conditions and the following disclaimer in
00022  *    the documentation and/or other materials provided with the
00023  *    distribution.
00024  *
00025  * 3. The end-user documentation included with the redistribution, if
00026  *    any, must include the following acknowlegement:
00027  *       "This product includes software developed by the
00028  *        Apache Software Foundation (http://www.apache.org/)."
00029  *    Alternately, this acknowlegement may appear in the software itself,
00030  *    if and wherever such third-party acknowlegements normally appear.
00031  *
00032  * 4. The names "The Jakarta Project", "Commons", and "Apache Software
00033  *    Foundation" must not be used to endorse or promote products derived
00034  *    from this software without prior written permission. For written
00035  *    permission, please contact apache@apache.org.
00036  *
00037  * 5. Products derived from this software may not be called "Apache"
00038  *    nor may "Apache" appear in their names without prior written
00039  *    permission of the Apache Group.
00040  *
00041  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
00042  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00043  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00044  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
00045  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00046  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00047  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
00048  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00049  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00050  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
00051  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00052  * SUCH DAMAGE.
00053  * ====================================================================
00054  *
00055  * This software consists of voluntary contributions made by many
00056  * individuals on behalf of the Apache Software Foundation.  For more
00057  * information on the Apache Software Foundation, please see
00058  * <http://www.apache.org/>.
00059  *
00060  */
00061 
00062 
00063 package org.apache.commons.fileupload;
00064 
00065 
00066 import java.io.IOException;
00067 import java.io.InputStream;
00068 import java.io.OutputStream;
00069 import java.util.ArrayList;
00070 import java.util.HashMap;
00071 import java.util.List;
00072 import java.util.Map;
00073 import javax.servlet.http.HttpServletRequest;
00074 
00075 
00099 public abstract class FileUploadBase
00100 {
00101 
00102     // ---------------------------------------------------------- Class methods
00103 
00104 
00114     public static final boolean isMultipartContent(HttpServletRequest req)
00115     {
00116         String contentType = req.getHeader(CONTENT_TYPE);
00117         if (contentType == null)
00118         {
00119             return false;
00120         }
00121         if (contentType.startsWith(MULTIPART))
00122         {
00123             return true;
00124         }
00125         return false;
00126     }
00127 
00128 
00129     // ----------------------------------------------------- Manifest constants
00130 
00131 
00135     public static final String CONTENT_TYPE = "Content-type";
00136 
00137 
00141     public static final String CONTENT_DISPOSITION = "Content-disposition";
00142 
00143 
00147     public static final String FORM_DATA = "form-data";
00148 
00149 
00153     public static final String ATTACHMENT = "attachment";
00154 
00155 
00159     public static final String MULTIPART = "multipart/";
00160 
00161 
00165     public static final String MULTIPART_FORM_DATA = "multipart/form-data";
00166 
00167 
00171     public static final String MULTIPART_MIXED = "multipart/mixed";
00172 
00173 
00178     public static final int MAX_HEADER_SIZE = 1024;
00179 
00180 
00181     // ----------------------------------------------------------- Data members
00182 
00183 
00188     private long sizeMax = -1;
00189 
00190 
00194     private String headerEncoding;
00195 
00196 
00197     // ----------------------------------------------------- Property accessors
00198 
00199 
00205     public abstract FileItemFactory getFileItemFactory();
00206 
00207 
00213     public abstract void setFileItemFactory(FileItemFactory factory);
00214 
00215 
00224     public long getSizeMax()
00225     {
00226         return sizeMax;
00227     }
00228 
00229 
00238     public void setSizeMax(long sizeMax)
00239     {
00240         this.sizeMax = sizeMax;
00241     }
00242 
00243 
00251     public String getHeaderEncoding()
00252     {
00253         return headerEncoding;
00254     }
00255 
00256 
00264     public void setHeaderEncoding(String encoding)
00265     {
00266         headerEncoding = encoding;
00267     }
00268 
00269 
00270     // --------------------------------------------------------- Public methods
00271 
00272 
00286     public List /* FileItem */ parseRequest(HttpServletRequest req)
00287         throws FileUploadException
00288     {
00289         if (null == req)
00290         {
00291             throw new NullPointerException("req parameter");
00292         }
00293 
00294         ArrayList items = new ArrayList();
00295         String contentType = req.getHeader(CONTENT_TYPE);
00296 
00297         if ((null == contentType) || (!contentType.startsWith(MULTIPART)))
00298         {
00299             throw new InvalidContentTypeException(
00300                 "the request doesn't contain a "
00301                 + MULTIPART_FORM_DATA
00302                 + " or "
00303                 + MULTIPART_MIXED
00304                 + " stream, content type header is "
00305                 + contentType);
00306         }
00307         int requestSize = req.getContentLength();
00308 
00309         if (requestSize == -1)
00310         {
00311             throw new UnknownSizeException(
00312                 "the request was rejected because it's size is unknown");
00313         }
00314 
00315         if (sizeMax >= 0 && requestSize > sizeMax)
00316         {
00317             throw new SizeLimitExceededException(
00318                 "the request was rejected because "
00319                 + "it's size exceeds allowed range");
00320         }
00321 
00322         try
00323         {
00324             int boundaryIndex = contentType.indexOf("boundary=");
00325             if (boundaryIndex < 0)
00326             {
00327                 throw new FileUploadException(
00328                         "the request was rejected because "
00329                         + "no multipart boundary was found");
00330             }
00331             byte[] boundary = contentType.substring(
00332                     boundaryIndex + 9).getBytes();
00333 
00334             InputStream input = req.getInputStream();
00335 
00336             MultipartStream multi = new MultipartStream(input, boundary);
00337             multi.setHeaderEncoding(headerEncoding);
00338 
00339             boolean nextPart = multi.skipPreamble();
00340             while (nextPart)
00341             {
00342                 Map headers = parseHeaders(multi.readHeaders());
00343                 String fieldName = getFieldName(headers);
00344                 if (fieldName != null)
00345                 {
00346                     String subContentType = getHeader(headers, CONTENT_TYPE);
00347                     if (subContentType != null && subContentType
00348                                                 .startsWith(MULTIPART_MIXED))
00349                     {
00350                         // Multiple files.
00351                         byte[] subBoundary =
00352                             subContentType.substring(
00353                                 subContentType
00354                                 .indexOf("boundary=") + 9).getBytes();
00355                         multi.setBoundary(subBoundary);
00356                         boolean nextSubPart = multi.skipPreamble();
00357                         while (nextSubPart)
00358                         {
00359                             headers = parseHeaders(multi.readHeaders());
00360                             if (getFileName(headers) != null)
00361                             {
00362                                 FileItem item =
00363                                         createItem(headers, false);
00364                                 OutputStream os = item.getOutputStream();
00365                                 try
00366                                 {
00367                                     multi.readBodyData(os);
00368                                 }
00369                                 finally
00370                                 {
00371                                     os.close();
00372                                 }
00373                                 items.add(item);
00374                             }
00375                             else
00376                             {
00377                                 // Ignore anything but files inside
00378                                 // multipart/mixed.
00379                                 multi.discardBodyData();
00380                             }
00381                             nextSubPart = multi.readBoundary();
00382                         }
00383                         multi.setBoundary(boundary);
00384                     }
00385                     else
00386                     {
00387                         if (getFileName(headers) != null)
00388                         {
00389                             // A single file.
00390                             FileItem item = createItem(headers, false);
00391                             OutputStream os = item.getOutputStream();
00392                             try
00393                             {
00394                                 multi.readBodyData(os);
00395                             }
00396                             finally
00397                             {
00398                                 os.close();
00399                             }
00400                             items.add(item);
00401                         }
00402                         else
00403                         {
00404                             // A form field.
00405                             FileItem item = createItem(headers, true);
00406                             OutputStream os = item.getOutputStream();
00407                             try
00408                             {
00409                                 multi.readBodyData(os);
00410                             }
00411                             finally
00412                             {
00413                                 os.close();
00414                             }
00415                             items.add(item);
00416                         }
00417                     }
00418                 }
00419                 else
00420                 {
00421                     // Skip this part.
00422                     multi.discardBodyData();
00423                 }
00424                 nextPart = multi.readBoundary();
00425             }
00426         }
00427         catch (IOException e)
00428         {
00429             throw new FileUploadException(
00430                 "Processing of " + MULTIPART_FORM_DATA
00431                     + " request failed. " + e.getMessage());
00432         }
00433 
00434         return items;
00435     }
00436 
00437 
00438     // ------------------------------------------------------ Protected methods
00439 
00440 
00449     protected String getFileName(Map /* String, String */ headers)
00450     {
00451         String fileName = null;
00452         String cd = getHeader(headers, CONTENT_DISPOSITION);
00453         if (cd.startsWith(FORM_DATA) || cd.startsWith(ATTACHMENT))
00454         {
00455             int start = cd.indexOf("filename=\"");
00456             int end = cd.indexOf('"', start + 10);
00457             if (start != -1 && end != -1)
00458             {
00459                 fileName = cd.substring(start + 10, end).trim();
00460             }
00461         }
00462         return fileName;
00463     }
00464 
00465 
00474     protected String getFieldName(Map /* String, String */ headers)
00475     {
00476         String fieldName = null;
00477         String cd = getHeader(headers, CONTENT_DISPOSITION);
00478         if (cd != null && cd.startsWith(FORM_DATA))
00479         {
00480             int start = cd.indexOf("name=\"");
00481             int end = cd.indexOf('"', start + 6);
00482             if (start != -1 && end != -1)
00483             {
00484                 fieldName = cd.substring(start + 6, end);
00485             }
00486         }
00487         return fieldName;
00488     }
00489 
00490 
00503     protected FileItem createItem(Map /* String, String */ headers,
00504                                   boolean isFormField)
00505         throws FileUploadException
00506     {
00507         return getFileItemFactory().createItem(getFieldName(headers),
00508                 getHeader(headers, CONTENT_TYPE),
00509                 isFormField,
00510                 getFileName(headers));
00511     }
00512 
00513 
00526     protected Map /* String, String */ parseHeaders(String headerPart)
00527     {
00528         Map headers = new HashMap();
00529         char buffer[] = new char[MAX_HEADER_SIZE];
00530         boolean done = false;
00531         int j = 0;
00532         int i;
00533         String header, headerName, headerValue;
00534         try
00535         {
00536             while (!done)
00537             {
00538                 i = 0;
00539                 // Copy a single line of characters into the buffer,
00540                 // omitting trailing CRLF.
00541                 while (i < 2 || buffer[i - 2] != '\r' || buffer[i - 1] != '\n')
00542                 {
00543                     buffer[i++] = headerPart.charAt(j++);
00544                 }
00545                 header = new String(buffer, 0, i - 2);
00546                 if (header.equals(""))
00547                 {
00548                     done = true;
00549                 }
00550                 else
00551                 {
00552                     if (header.indexOf(':') == -1)
00553                     {
00554                         // This header line is malformed, skip it.
00555                         continue;
00556                     }
00557                     headerName = header.substring(0, header.indexOf(':'))
00558                         .trim().toLowerCase();
00559                     headerValue =
00560                         header.substring(header.indexOf(':') + 1).trim();
00561                     if (getHeader(headers, headerName) != null)
00562                     {
00563                         // More that one heder of that name exists,
00564                         // append to the list.
00565                         headers.put(headerName,
00566                                     getHeader(headers, headerName) + ','
00567                                         + headerValue);
00568                     }
00569                     else
00570                     {
00571                         headers.put(headerName, headerValue);
00572                     }
00573                 }
00574             }
00575         }
00576         catch (IndexOutOfBoundsException e)
00577         {
00578             // Headers were malformed. continue with all that was
00579             // parsed.
00580         }
00581         return headers;
00582     }
00583 
00584 
00595     protected final String getHeader(Map /* String, String */ headers,
00596                                      String name)
00597     {
00598         return (String) headers.get(name.toLowerCase());
00599     }
00600 
00601 
00605     public static class InvalidContentTypeException
00606         extends FileUploadException
00607     {
00612         public InvalidContentTypeException()
00613         {
00614             super();
00615         }
00616 
00623         public InvalidContentTypeException(String message)
00624         {
00625             super(message);
00626         }
00627     }
00628 
00629 
00633     public static class UnknownSizeException
00634         extends FileUploadException
00635     {
00640         public UnknownSizeException()
00641         {
00642             super();
00643         }
00644 
00651         public UnknownSizeException(String message)
00652         {
00653             super(message);
00654         }
00655     }
00656 
00657 
00661     public static class SizeLimitExceededException
00662         extends FileUploadException
00663     {
00668         public SizeLimitExceededException()
00669         {
00670             super();
00671         }
00672 
00679         public SizeLimitExceededException(String message)
00680         {
00681             super(message);
00682         }
00683     }
00684 
00685 }

Generated on Mon Jan 11 21:19:14 2010 for OpenMobileIS by  doxygen 1.5.4