org.apache.myfaces.webapp.filter.portlet.PortletChacheFileSizeErrorsFileUpload.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.myfaces.webapp.filter.portlet.PortletChacheFileSizeErrorsFileUpload.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.myfaces.webapp.filter.portlet;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import javax.portlet.ActionRequest;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileItemHeaders;
import org.apache.commons.fileupload.FileItemHeadersSupport;
import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.FileUpload;
import org.apache.commons.fileupload.FileUploadBase;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.RequestContext;
import org.apache.commons.fileupload.portlet.PortletFileUpload;
import org.apache.commons.fileupload.portlet.PortletRequestContext;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.util.LimitedInputStream;
import org.apache.commons.fileupload.util.Streams;

/**
 * Custom implementation of PortletFileUpload intended to parse request but it
 * catch and swallow FileSizeLimitExceededExceptions in order to return as
 * many usable items as possible.
 * 
 * <p>
 * NOTE: This class should be used(instantiated) only by 
 * PortletMultipartRequestWrapper. By that reason, it could be changed
 * or removed in the future.
 * </p>
 * 
 * @since 1.1.9
 * @author Phillip Webb
 * @author Leonardo Uribe (latest modification by $Author: lu4242 $)
 * @version $Revision: 703744 $ $Date: 2008-10-11 17:28:20 -0500 (Sat, 11 Oct 2008) $
 *
 */
public class PortletChacheFileSizeErrorsFileUpload extends PortletFileUpload {

    public PortletChacheFileSizeErrorsFileUpload() {
        super();
    }

    public PortletChacheFileSizeErrorsFileUpload(FileItemFactory fileItemFactory) {
        super(fileItemFactory);
    }

    /**
     * Determine the length of an uploaded file as indicated by the header.
     * 
     * @param pHeaders
     * @return length or -1
     */
    private long getContentLength(FileItemHeaders pHeaders) {
        try {
            return Long.parseLong(pHeaders.getHeader(FileUploadBase.CONTENT_LENGTH));
        } catch (Exception e) {
            return -1;
        }
    }

    /**
     * Similar to {@link ServletFileUpload#parseRequest(RequestContext)} but will
     * catch and swallow FileSizeLimitExceededExceptions in order to return as
     * many usable items as possible.
     * 
     * @param fileUpload
     * @return List of {@link FileItem} excluding any that exceed max size.  
     * @throws FileUploadException
     */
    public List parseRequestCatchingFileSizeErrors(ActionRequest request, FileUpload fileUpload)
            throws FileUploadException {
        try {
            List items = new ArrayList();

            // The line below throws a SizeLimitExceededException (wrapped by a
            // FileUploadIOException) if the request is longer than the max size
            // allowed by fileupload requests (FileUpload.getSizeMax)
            // But note that if the request does not send proper headers this check
            // just will not do anything and we still have to check it again.
            FileItemIterator iter = fileUpload.getItemIterator(new PortletRequestContext(request));

            FileItemFactory fac = fileUpload.getFileItemFactory();
            if (fac == null) {
                throw new NullPointerException("No FileItemFactory has been set.");
            }

            long maxFileSize = this.getFileSizeMax();
            long maxSize = this.getSizeMax();
            boolean checkMaxSize = false;

            if (maxFileSize == -1L) {
                //The max allowed file size should be approximate to the maxSize
                maxFileSize = maxSize;
            }
            if (maxSize != -1L) {
                checkMaxSize = true;
            }

            while (iter.hasNext()) {
                final FileItemStream item = iter.next();
                FileItem fileItem = fac.createItem(item.getFieldName(), item.getContentType(), item.isFormField(),
                        item.getName());

                long allowedLimit = 0L;
                try {
                    if (maxFileSize != -1L || checkMaxSize) {
                        if (checkMaxSize) {
                            allowedLimit = maxSize > maxFileSize ? maxFileSize : maxSize;
                        } else {
                            //Just put the limit
                            allowedLimit = maxFileSize;
                        }

                        long contentLength = getContentLength(item.getHeaders());

                        //If we have a content length in the header we can use it
                        if (contentLength != -1L && contentLength > allowedLimit) {
                            throw new FileUploadIOException(new FileSizeLimitExceededException(
                                    "The field " + item.getFieldName() + " exceeds its maximum permitted "
                                            + " size of " + allowedLimit + " characters.",
                                    contentLength, allowedLimit));
                        }

                        //Otherwise we must limit the input as it arrives (NOTE: we cannot rely
                        //on commons upload to throw this exception as it will close the 
                        //underlying stream
                        final InputStream itemInputStream = item.openStream();

                        InputStream limitedInputStream = new LimitedInputStream(itemInputStream, allowedLimit) {
                            protected void raiseError(long pSizeMax, long pCount) throws IOException {
                                throw new FileUploadIOException(new FileSizeLimitExceededException(
                                        "The field " + item.getFieldName() + " exceeds its maximum permitted "
                                                + " size of " + pSizeMax + " characters.",
                                        pCount, pSizeMax));
                            }
                        };

                        //Copy from the limited stream
                        long bytesCopied = Streams.copy(limitedInputStream, fileItem.getOutputStream(), true);

                        // Decrement the bytesCopied values from maxSize, so the next file copied 
                        // takes into account this value when allowedLimit var is calculated
                        // Note the invariant before the line is maxSize >= bytesCopied, since if this
                        // is not true a FileUploadIOException is thrown first.
                        maxSize -= bytesCopied;
                    } else {
                        //We can just copy the data
                        Streams.copy(item.openStream(), fileItem.getOutputStream(), true);
                    }
                } catch (FileUploadIOException e) {
                    try {
                        throw (FileUploadException) e.getCause();
                    } catch (FileUploadBase.FileSizeLimitExceededException se) {
                        request.setAttribute("org.apache.myfaces.custom.fileupload.exception",
                                "fileSizeLimitExceeded");
                        String fieldName = fileItem.getFieldName();
                        request.setAttribute("org.apache.myfaces.custom.fileupload." + fieldName + ".maxSize",
                                new Integer((int) allowedLimit));
                    }
                } catch (IOException e) {
                    throw new IOFileUploadException("Processing of " + FileUploadBase.MULTIPART_FORM_DATA
                            + " request failed. " + e.getMessage(), e);
                }
                if (fileItem instanceof FileItemHeadersSupport) {
                    final FileItemHeaders fih = item.getHeaders();
                    ((FileItemHeadersSupport) fileItem).setHeaders(fih);
                }
                if (fileItem != null) {
                    items.add(fileItem);
                }
            }
            return items;
        } catch (FileUploadIOException e) {
            throw (FileUploadException) e.getCause();
        } catch (IOException e) {
            throw new FileUploadException(e.getMessage(), e);
        }
    }
}