UploadFilter.java

/*
 * Copyright (c) 2002-2022, City of Paris
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  1. Redistributions of source code must retain the above copyright notice
 *     and the following disclaimer.
 *
 *  2. Redistributions in binary form must reproduce the above copyright notice
 *     and the following disclaimer in the documentation and/or other materials
 *     provided with the distribution.
 *
 *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
 *     contributors may be used to endorse or promote products derived from
 *     this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * License 1.0
 */
package fr.paris.lutece.portal.web.upload;

import java.io.IOException;
import java.text.DecimalFormat;
import java.text.NumberFormat;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException;
import org.apache.commons.fileupload.FileUploadException;

import fr.paris.lutece.portal.service.util.AppLogService;
import fr.paris.lutece.util.http.MultipartUtil;

/**
 * Upload filter
 */
public abstract class UploadFilter implements Filter
{
    private static final String PROPERTY_TITLE_FILE_SIZE_LIMIT_EXCEEDED = "portal.util.message.titleDefault";
    private static final String PROPERTY_MESSAGE_FILE_SIZE_LIMIT_EXCEEDED = "portal.util.message.fileSizeLimitExceeded";
    private static final int KILO_BYTE = 1024;
    private static final String SIZE_THRESHOLD = "sizeThreshold";
    private static final String REQUEST_SIZE_MAX = "requestSizeMax";
    private static final String ACTIVATE_NORMALIZE_FILE_NAME = "activateNormalizeFileName";
    private int _nSizeThreshold = -1;
    private long _nRequestSizeMax = -1;
    private boolean _bActivateNormalizeFileName;

    /**
     * Forward the error message url depends site or admin implementation.
     *
     * @param request
     *            The http request
     * @param strMessageKey
     *            the str message key
     * @param messageArgs
     *            the message args
     * @param strTitleKey
     *            the str title key
     * @return Message
     */
    protected abstract String getMessageRelativeUrl( HttpServletRequest request, String strMessageKey, Object [ ] messageArgs, String strTitleKey );

    /**
     * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
     * @param config
     *            The FilterConfig
     * @throws ServletException
     *             The ServletException
     */
    @Override
    public void init( FilterConfig config ) throws ServletException
    {
        try
        {
            String paramValue = config.getInitParameter( SIZE_THRESHOLD );

            if ( paramValue != null )
            {
                _nSizeThreshold = Integer.parseInt( paramValue );
            }

            paramValue = config.getInitParameter( REQUEST_SIZE_MAX );

            if ( paramValue != null )
            {
                _nRequestSizeMax = Long.parseLong( paramValue );
            }

            paramValue = config.getInitParameter( ACTIVATE_NORMALIZE_FILE_NAME );

            if ( paramValue != null )
            {
                _bActivateNormalizeFileName = Boolean.valueOf( paramValue );
            }
        }
        catch( NumberFormatException ex )
        {
            AppLogService.error( ex.getMessage( ), ex );
            throw new ServletException( ex.getMessage( ), ex );
        }
    }

    /**
     * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
     * @param request
     *            The ServletRequest
     * @param response
     *            The ServletResponse
     * @param chain
     *            The FilterChain
     * @throws IOException
     *             The IOException
     * @throws ServletException
     *             The SerletException
     */
    @Override
    public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain ) throws IOException, ServletException
    {
        HttpServletRequest httpRequest = (HttpServletRequest) request;

        if ( !MultipartUtil.isMultipart( httpRequest ) )
        {
            chain.doFilter( request, response );
        }
        else
        {
            try
            {
                MultipartHttpServletRequest multiHtppRequest = MultipartUtil.convert( _nSizeThreshold, _nRequestSizeMax, _bActivateNormalizeFileName,
                        httpRequest );
                chain.doFilter( multiHtppRequest, response );
            }
            catch( SizeLimitExceededException e )
            {
                AppLogService.error( e.getMessage( ), e );

                Object [ ] args = {
                        getDisplaySize( )
                };
                ( (HttpServletResponse) response ).sendRedirect(
                        getMessageRelativeUrl( httpRequest, PROPERTY_MESSAGE_FILE_SIZE_LIMIT_EXCEEDED, args, PROPERTY_TITLE_FILE_SIZE_LIMIT_EXCEEDED ) );
            }
            catch( FileUploadException e )
            {
                AppLogService.error( e.getMessage( ), e );
                throw new ServletException( "Unkown error occured during the upload", e );
            }
        }
    }

    /**
     * Get the max size of upload file
     *
     * @return The max size
     */
    public long getRequestSizeMax( )
    {
        return _nRequestSizeMax;
    }

    /**
     * Default implementation for subclasses
     */
    @Override
    public void destroy( )
    {
        // Do nothing
    }

    /**
     *
     * @return the size of the request to display in the error message
     */
    private String getDisplaySize( )
    {
        long lSizeMax = getRequestSizeMax( );
        DecimalFormat decimalFormat = (DecimalFormat) NumberFormat.getInstance( );
        decimalFormat.applyPattern( "#" );

        return ( lSizeMax >= KILO_BYTE ) ? ( String.valueOf( lSizeMax / KILO_BYTE ) ) : ( decimalFormat.format( lSizeMax / KILO_BYTE ) );
    }
}