View Javadoc
1   /*
2    * Copyright (c) 2002-2025, City of Paris
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met:
8    *
9    *  1. Redistributions of source code must retain the above copyright notice
10   *     and the following disclaimer.
11   *
12   *  2. Redistributions in binary form must reproduce the above copyright notice
13   *     and the following disclaimer in the documentation and/or other materials
14   *     provided with the distribution.
15   *
16   *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
17   *     contributors may be used to endorse or promote products derived from
18   *     this software without specific prior written permission.
19   *
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
24   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   * POSSIBILITY OF SUCH DAMAGE.
31   *
32   * License 1.0
33   */
34  package fr.paris.lutece.portal.web.upload;
35  
36  import java.io.IOException;
37  import java.text.DecimalFormat;
38  import java.text.NumberFormat;
39  
40  import javax.servlet.Filter;
41  import javax.servlet.FilterChain;
42  import javax.servlet.FilterConfig;
43  import javax.servlet.ServletException;
44  import javax.servlet.ServletRequest;
45  import javax.servlet.ServletResponse;
46  import javax.servlet.http.HttpServletRequest;
47  import javax.servlet.http.HttpServletResponse;
48  
49  import org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException;
50  import org.apache.commons.fileupload.FileUploadException;
51  
52  import fr.paris.lutece.portal.service.util.AppLogService;
53  import fr.paris.lutece.portal.web.xss.XSSRequestWrapper;
54  import fr.paris.lutece.util.http.MultipartUtil;
55  
56  /**
57   * Upload filter
58   */
59  public abstract class UploadFilter implements Filter
60  {
61      private static final String PROPERTY_TITLE_FILE_SIZE_LIMIT_EXCEEDED = "portal.util.message.titleDefault";
62      private static final String PROPERTY_MESSAGE_FILE_SIZE_LIMIT_EXCEEDED = "portal.util.message.fileSizeLimitExceeded";
63      private static final int KILO_BYTE = 1024;
64      private static final String SIZE_THRESHOLD = "sizeThreshold";
65      private static final String REQUEST_SIZE_MAX = "requestSizeMax";
66      private static final String ACTIVATE_NORMALIZE_FILE_NAME = "activateNormalizeFileName";
67      private int _nSizeThreshold = -1;
68      private long _nRequestSizeMax = -1;
69      private boolean _bActivateNormalizeFileName;
70  
71      /**
72       * Forward the error message url depends site or admin implementation.
73       *
74       * @param request
75       *            The http request
76       * @param strMessageKey
77       *            the str message key
78       * @param messageArgs
79       *            the message args
80       * @param strTitleKey
81       *            the str title key
82       * @return Message
83       */
84      protected abstract String getMessageRelativeUrl( HttpServletRequest request, String strMessageKey, Object [ ] messageArgs, String strTitleKey );
85  
86      /**
87       * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
88       * @param config
89       *            The FilterConfig
90       * @throws ServletException
91       *             The ServletException
92       */
93      @Override
94      public void init( FilterConfig config ) throws ServletException
95      {
96          try
97          {
98              String paramValue = config.getInitParameter( SIZE_THRESHOLD );
99  
100             if ( paramValue != null )
101             {
102                 _nSizeThreshold = Integer.parseInt( paramValue );
103             }
104 
105             paramValue = config.getInitParameter( REQUEST_SIZE_MAX );
106 
107             if ( paramValue != null )
108             {
109                 _nRequestSizeMax = Long.parseLong( paramValue );
110             }
111 
112             paramValue = config.getInitParameter( ACTIVATE_NORMALIZE_FILE_NAME );
113 
114             if ( paramValue != null )
115             {
116                 _bActivateNormalizeFileName = Boolean.valueOf( paramValue );
117             }
118         }
119         catch( NumberFormatException ex )
120         {
121             AppLogService.error( ex.getMessage( ), ex );
122             throw new ServletException( ex.getMessage( ), ex );
123         }
124     }
125 
126     /**
127      * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
128      * @param request
129      *            The ServletRequest
130      * @param response
131      *            The ServletResponse
132      * @param chain
133      *            The FilterChain
134      * @throws IOException
135      *             The IOException
136      * @throws ServletException
137      *             The SerletException
138      */
139     @Override
140     public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain ) throws IOException, ServletException
141     {
142         HttpServletRequest httpRequest = (HttpServletRequest) request;
143 
144         if ( !MultipartUtil.isMultipart( httpRequest ) )
145         {
146             chain.doFilter( request, response );
147         }
148         else
149         {
150             try
151             {
152         	
153                 MultipartHttpServletRequest multiHtppRequest = MultipartUtil.convert( _nSizeThreshold, _nRequestSizeMax, _bActivateNormalizeFileName,
154                         httpRequest , httpRequest instanceof XSSRequestWrapper );
155                 chain.doFilter( multiHtppRequest, response );
156             }
157             catch( SizeLimitExceededException e )
158             {
159                 AppLogService.error( e.getMessage( ), e );
160 
161                 Object [ ] args = {
162                         getDisplaySize( )
163                 };
164                 ( (HttpServletResponse) response ).sendRedirect(
165                         getMessageRelativeUrl( httpRequest, PROPERTY_MESSAGE_FILE_SIZE_LIMIT_EXCEEDED, args, PROPERTY_TITLE_FILE_SIZE_LIMIT_EXCEEDED ) );
166             }
167             catch( FileUploadException e )
168             {
169                 AppLogService.error( e.getMessage( ), e );
170                 throw new ServletException( "Unkown error occured during the upload", e );
171             }
172         }
173     }
174 
175     /**
176      * Get the max size of upload file
177      *
178      * @return The max size
179      */
180     public long getRequestSizeMax( )
181     {
182         return _nRequestSizeMax;
183     }
184 
185     /**
186      * Default implementation for subclasses
187      */
188     @Override
189     public void destroy( )
190     {
191         // Do nothing
192     }
193 
194     /**
195      *
196      * @return the size of the request to display in the error message
197      */
198     private String getDisplaySize( )
199     {
200         long lSizeMax = getRequestSizeMax( );
201         DecimalFormat decimalFormat = (DecimalFormat) NumberFormat.getInstance( );
202         decimalFormat.applyPattern( "#" );
203 
204         return ( lSizeMax >= KILO_BYTE ) ? ( String.valueOf( lSizeMax / KILO_BYTE ) ) : ( decimalFormat.format( lSizeMax / KILO_BYTE ) );
205     }
206 }