FileDocCategorySizeDatePackage
FileUploadBase.javaAPI DocApache Tomcat 6.0.1420768Fri Jul 20 04:20:32 BST 2007org.apache.tomcat.util.http.fileupload

FileUploadBase

public abstract class FileUploadBase extends Object

High level API for processing file uploads.

This class handles multiple files per single HTML widget, sent using multipart/mixed encoding type, as specified by RFC 1867. Use {@link #parseRequest(HttpServletRequest)} to acquire a list of {@link org.apache.tomcat.util.http.fileupload.FileItem}s associated with a given HTML widget.

How the data for individual parts is stored is determined by the factory used to create them; a given part may be in memory, on disk, or somewhere else.

author
Rafal Krzewski
author
Daniel Rall
author
Jason van Zyl
author
John McNally
author
Martin Cooper
author
Sean C. Sullivan
version
$Id: FileUploadBase.java 467222 2006-10-24 03:17:11Z markt $

Fields Summary
public static final String
CONTENT_TYPE
HTTP content type header name.
public static final String
CONTENT_DISPOSITION
HTTP content disposition header name.
public static final String
FORM_DATA
Content-disposition value for form data.
public static final String
ATTACHMENT
Content-disposition value for file attachment.
public static final String
MULTIPART
Part of HTTP content type header.
public static final String
MULTIPART_FORM_DATA
HTTP content type header for multipart forms.
public static final String
MULTIPART_MIXED
HTTP content type header for multiple uploads.
public static final int
MAX_HEADER_SIZE
The maximum length of a single header line that will be parsed (1024 bytes).
private long
sizeMax
The maximum size permitted for an uploaded file. A value of -1 indicates no maximum.
private String
headerEncoding
The content encoding to use when reading part headers.
Constructors Summary
Methods Summary
protected FileItemcreateItem(java.util.Map headers, boolean isFormField)
Creates a new {@link FileItem} instance.

param
headers A Map containing the HTTP request headers.
param
isFormField Whether or not this item is a form field, as opposed to a file.
return
A newly created FileItem instance.
exception
FileUploadException if an error occurs.

        return getFileItemFactory().createItem(getFieldName(headers),
                getHeader(headers, CONTENT_TYPE),
                isFormField,
                getFileName(headers));
    
protected java.lang.StringgetFieldName(java.util.Map headers)
Retrieves the field name from the Content-disposition header.

param
headers A Map containing the HTTP request headers.
return
The field name for the current encapsulation.

        String fieldName = null;
        String cd = getHeader(headers, CONTENT_DISPOSITION);
        if (cd != null && cd.startsWith(FORM_DATA))
        {
            int start = cd.indexOf("name=\"");
            int end = cd.indexOf('"", start + 6);
            if (start != -1 && end != -1)
            {
                fieldName = cd.substring(start + 6, end);
            }
        }
        return fieldName;
    
public abstract FileItemFactorygetFileItemFactory()
Returns the factory class used when creating file items.

return
The factory class for new file items.

protected java.lang.StringgetFileName(java.util.Map headers)
Retrieves the file name from the Content-disposition header.

param
headers A Map containing the HTTP request headers.
return
The file name for the current encapsulation.

        String fileName = null;
        String cd = getHeader(headers, CONTENT_DISPOSITION);
        if (cd.startsWith(FORM_DATA) || cd.startsWith(ATTACHMENT))
        {
            int start = cd.indexOf("filename=\"");
            int end = cd.indexOf('"", start + 10);
            if (start != -1 && end != -1)
            {
                fileName = cd.substring(start + 10, end).trim();
            }
        }
        return fileName;
    
protected final java.lang.StringgetHeader(java.util.Map headers, java.lang.String name)
Returns the header with the specified name from the supplied map. The header lookup is case-insensitive.

param
headers A Map containing the HTTP request headers.
param
name The name of the header to return.
return
The value of specified header, or a comma-separated list if there were multiple headers of that name.

        return (String) headers.get(name.toLowerCase());
    
public java.lang.StringgetHeaderEncoding()
Retrieves the character encoding used when reading the headers of an individual part. When not specified, or null, the platform default encoding is used.

return
The encoding used to read part headers.

        return headerEncoding;
    
public longgetSizeMax()
Returns the maximum allowed upload size.

return
The maximum allowed size, in bytes.
see
#setSizeMax(long)



    // ----------------------------------------------------- Property accessors


                          
       


                            
        


                        
      
    
        return sizeMax;
    
public static final booleanisMultipartContent(javax.servlet.http.HttpServletRequest req)
Utility method that determines whether the request contains multipart content.

param
req The servlet request to be evaluated. Must be non-null.
return
true if the request is multipart; false otherwise.

        String contentType = req.getHeader(CONTENT_TYPE);
        if (contentType == null)
        {
            return false;
        }
        if (contentType.startsWith(MULTIPART))
        {
            return true;
        }
        return false;
    
protected java.util.MapparseHeaders(java.lang.String headerPart)

Parses the header-part and returns as key/value pairs.

If there are multiple headers of the same names, the name will map to a comma-separated list containing the values.

param
headerPart The header-part of the current encapsulation.
return
A Map containing the parsed HTTP request headers.

        Map headers = new HashMap();
        char buffer[] = new char[MAX_HEADER_SIZE];
        boolean done = false;
        int j = 0;
        int i;
        String header, headerName, headerValue;
        try
        {
            while (!done)
            {
                i = 0;
                // Copy a single line of characters into the buffer,
                // omitting trailing CRLF.
                while (i < 2 || buffer[i - 2] != '\r" || buffer[i - 1] != '\n")
                {
                    buffer[i++] = headerPart.charAt(j++);
                }
                header = new String(buffer, 0, i - 2);
                if (header.equals(""))
                {
                    done = true;
                }
                else
                {
                    if (header.indexOf(':") == -1)
                    {
                        // This header line is malformed, skip it.
                        continue;
                    }
                    headerName = header.substring(0, header.indexOf(':"))
                        .trim().toLowerCase();
                    headerValue =
                        header.substring(header.indexOf(':") + 1).trim();
                    if (getHeader(headers, headerName) != null)
                    {
                        // More that one heder of that name exists,
                        // append to the list.
                        headers.put(headerName,
                                    getHeader(headers, headerName) + ',"
                                        + headerValue);
                    }
                    else
                    {
                        headers.put(headerName, headerValue);
                    }
                }
            }
        }
        catch (IndexOutOfBoundsException e)
        {
            // Headers were malformed. continue with all that was
            // parsed.
        }
        return headers;
    
public java.util.ListparseRequest(javax.servlet.http.HttpServletRequest req)
Processes an RFC 1867 compliant multipart/form-data stream. If files are stored on disk, the path is given by getRepository().

param
req The servlet request to be parsed.
return
A list of FileItem instances parsed from the request, in the order that they were transmitted.
exception
FileUploadException if there are problems reading/parsing the request or storing files.

        if (null == req)
        {
            throw new NullPointerException("req parameter");
        }

        ArrayList items = new ArrayList();
        String contentType = req.getHeader(CONTENT_TYPE);

        if ((null == contentType) || (!contentType.startsWith(MULTIPART)))
        {
            throw new InvalidContentTypeException(
                "the request doesn't contain a "
                + MULTIPART_FORM_DATA
                + " or "
                + MULTIPART_MIXED
                + " stream, content type header is "
                + contentType);
        }
        int requestSize = req.getContentLength();

        if (requestSize == -1)
        {
            throw new UnknownSizeException(
                "the request was rejected because it's size is unknown");
        }

        if (sizeMax >= 0 && requestSize > sizeMax)
        {
            throw new SizeLimitExceededException(
                "the request was rejected because "
                + "it's size exceeds allowed range");
        }

        try
        {
            int boundaryIndex = contentType.indexOf("boundary=");
            if (boundaryIndex < 0)
            {
                throw new FileUploadException(
                        "the request was rejected because "
                        + "no multipart boundary was found");
            }
            byte[] boundary = contentType.substring(
                    boundaryIndex + 9).getBytes();

            InputStream input = req.getInputStream();

            MultipartStream multi = new MultipartStream(input, boundary);
            multi.setHeaderEncoding(headerEncoding);

            boolean nextPart = multi.skipPreamble();
            while (nextPart)
            {
                Map headers = parseHeaders(multi.readHeaders());
                String fieldName = getFieldName(headers);
                if (fieldName != null)
                {
                    String subContentType = getHeader(headers, CONTENT_TYPE);
                    if (subContentType != null && subContentType
                                                .startsWith(MULTIPART_MIXED))
                    {
                        // Multiple files.
                        byte[] subBoundary =
                            subContentType.substring(
                                subContentType
                                .indexOf("boundary=") + 9).getBytes();
                        multi.setBoundary(subBoundary);
                        boolean nextSubPart = multi.skipPreamble();
                        while (nextSubPart)
                        {
                            headers = parseHeaders(multi.readHeaders());
                            if (getFileName(headers) != null)
                            {
                                FileItem item =
                                        createItem(headers, false);
                                OutputStream os = item.getOutputStream();
                                try
                                {
                                    multi.readBodyData(os);
                                }
                                finally
                                {
                                    os.close();
                                }
                                items.add(item);
                            }
                            else
                            {
                                // Ignore anything but files inside
                                // multipart/mixed.
                                multi.discardBodyData();
                            }
                            nextSubPart = multi.readBoundary();
                        }
                        multi.setBoundary(boundary);
                    }
                    else
                    {
                        if (getFileName(headers) != null)
                        {
                            // A single file.
                            FileItem item = createItem(headers, false);
                            OutputStream os = item.getOutputStream();
                            try
                            {
                                multi.readBodyData(os);
                            }
                            finally
                            {
                                os.close();
                            }
                            items.add(item);
                        }
                        else
                        {
                            // A form field.
                            FileItem item = createItem(headers, true);
                            OutputStream os = item.getOutputStream();
                            try
                            {
                                multi.readBodyData(os);
                            }
                            finally
                            {
                                os.close();
                            }
                            items.add(item);
                        }
                    }
                }
                else
                {
                    // Skip this part.
                    multi.discardBodyData();
                }
                nextPart = multi.readBoundary();
            }
        }
        catch (IOException e)
        {
            throw new FileUploadException(
                "Processing of " + MULTIPART_FORM_DATA
                    + " request failed. " + e.getMessage());
        }

        return items;
    
public abstract voidsetFileItemFactory(FileItemFactory factory)
Sets the factory class to use when creating file items.

param
factory The factory class for new file items.

public voidsetHeaderEncoding(java.lang.String encoding)
Specifies the character encoding to be used when reading the headers of individual parts. When not specified, or null, the platform default encoding is used.

param
encoding The encoding used to read part headers.

        headerEncoding = encoding;
    
public voidsetSizeMax(long sizeMax)
Sets the maximum allowed upload size. If negative, there is no maximum.

param
sizeMax The maximum allowed size, in bytes, or -1 for no maximum.
see
#getSizeMax()

        this.sizeMax = sizeMax;