View Javadoc
1   /*
2    * Copyright (c) 2002-2022, 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.util.http;
35  
36  import fr.paris.lutece.portal.service.html.EncodingService;
37  import fr.paris.lutece.portal.web.upload.MultipartHttpServletRequest;
38  import fr.paris.lutece.portal.web.upload.NormalizeFileItem;
39  
40  import org.apache.commons.fileupload.FileItem;
41  import org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException;
42  import org.apache.commons.fileupload.FileUploadException;
43  import org.apache.commons.fileupload.disk.DiskFileItemFactory;
44  import org.apache.commons.fileupload.servlet.ServletFileUpload;
45  import org.apache.commons.lang3.StringUtils;
46  
47  import java.io.UnsupportedEncodingException;
48  
49  import java.util.ArrayList;
50  import java.util.HashMap;
51  import java.util.List;
52  import java.util.Map;
53  import java.util.Optional;
54  
55  import javax.servlet.http.HttpServletRequest;
56  
57  /**
58   *
59   * MultipartUtil
60   *
61   */
62  public final class MultipartUtil
63  {
64      /**
65       * Private constructor
66       */
67      private MultipartUtil( )
68      {
69      }
70  
71      /**
72       * Check if the given HTTP request has multipart content
73       * 
74       * @param request
75       *            the HTTP request
76       * @return true if it has multipart content, false otherwise
77       */
78      public static boolean isMultipart( HttpServletRequest request )
79      {
80          return ServletFileUpload.isMultipartContent( request );
81      }
82  
83      /**
84       * Convert a HTTP request to a {@link MultipartHttpServletRequest}
85       * 
86       * @param nSizeThreshold
87       *            the size threshold
88       * @param nRequestSizeMax
89       *            the request size max
90       * @param bActivateNormalizeFileName
91       *            true if the file name must be normalized, false otherwise
92       * @param request
93       *            the HTTP request
94       * @return a {@link MultipartHttpServletRequest}, null if the request does not have a multipart content
95       * @throws SizeLimitExceededException
96       *             exception if the file size is too big
97       * @throws FileUploadException
98       *             exception if an unknown error has occurred
99       */
100     public static MultipartHttpServletRequest convert( int nSizeThreshold, long nRequestSizeMax, boolean bActivateNormalizeFileName,
101             HttpServletRequest request ) throws FileUploadException
102     {
103         if ( !isMultipart( request ) )
104         {
105             return null;
106         }
107 
108         // Create a factory for disk-based file items
109         DiskFileItemFactory factory = new DiskFileItemFactory( );
110 
111         // Set factory constraints
112         factory.setSizeThreshold( nSizeThreshold );
113 
114         // Create a new file upload handler
115         ServletFileUpload upload = new ServletFileUpload( factory );
116 
117         // Set overall request size constraint
118         upload.setSizeMax( nRequestSizeMax );
119 
120         // get encoding to be used
121         String strEncoding = Optional.ofNullable( request.getCharacterEncoding( ) ).orElse( EncodingService.getEncoding( ) );
122 
123         Map<String, List<FileItem>> mapFiles = new HashMap<>( );
124         Map<String, String [ ]> mapParameters = new HashMap<>( );
125 
126         List<FileItem> listItems = upload.parseRequest( request );
127 
128         // Process the uploaded items
129         for ( FileItem item : listItems )
130         {
131             processItem( item, strEncoding, bActivateNormalizeFileName, mapFiles, mapParameters );
132         }
133 
134         return new MultipartHttpServletRequest( request, mapFiles, mapParameters );
135     }
136 
137     private static void processItem( FileItem item, String strEncoding, boolean bActivateNormalizeFileName, Map<String, List<FileItem>> mapFiles,
138             Map<String, String [ ]> mapParameters )
139     {
140         if ( item.isFormField( ) )
141         {
142             String strValue = StringUtils.EMPTY;
143 
144             if ( item.getSize( ) > 0 )
145             {
146                 try
147                 {
148                     strValue = item.getString( strEncoding );
149                 }
150                 catch( UnsupportedEncodingException ex )
151                 {
152                     // if encoding problem, try with system encoding
153                     strValue = item.getString( );
154                 }
155             }
156 
157             // check if item of same name already in map
158             String [ ] curParam = mapParameters.get( item.getFieldName( ) );
159 
160             if ( curParam == null )
161             {
162                 // simple form field
163                 mapParameters.put( item.getFieldName( ), new String [ ] {
164                         strValue
165                 } );
166             }
167             else
168             {
169                 // array of simple form fields
170                 String [ ] newArray = new String [ curParam.length + 1];
171                 System.arraycopy( curParam, 0, newArray, 0, curParam.length );
172                 newArray [curParam.length] = strValue;
173                 mapParameters.put( item.getFieldName( ), newArray );
174             }
175         }
176         else
177         {
178             // multipart file field, if the parameter filter ActivateNormalizeFileName is
179             // set to true
180             // all file name will be normalize
181             FileItem fileItem = bActivateNormalizeFileName ? new NormalizeFileItem( item ) : item;
182             List<FileItem> listFileItem = mapFiles.get( fileItem.getFieldName( ) );
183 
184             if ( listFileItem != null )
185             {
186                 listFileItem.add( fileItem );
187             }
188             else
189             {
190                 listFileItem = new ArrayList<>( 1 );
191                 listFileItem.add( fileItem );
192                 mapFiles.put( fileItem.getFieldName( ), listFileItem );
193             }
194         }
195     }
196 }