View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.webapp.filter;
20  
21  import java.io.File;
22  import java.io.UnsupportedEncodingException;
23  import java.util.Collections;
24  import java.util.Enumeration;
25  import java.util.HashMap;
26  import java.util.HashSet;
27  import java.util.Iterator;
28  import java.util.List;
29  import java.util.Map;
30  
31  import javax.servlet.http.HttpServletRequest;
32  import javax.servlet.http.HttpServletRequestWrapper;
33  
34  import org.apache.commons.fileupload.FileItem;
35  import org.apache.commons.fileupload.FileUploadBase;
36  import org.apache.commons.fileupload.FileUploadException;
37  import org.apache.commons.fileupload.disk.DiskFileItemFactory;
38  import org.apache.commons.fileupload.servlet.ServletFileUpload;
39  import org.apache.commons.logging.Log;
40  import org.apache.commons.logging.LogFactory;
41  import org.apache.myfaces.webapp.filter.servlet.ServletChacheFileSizeErrorsFileUpload;
42  
43  /**
44   * @since 1.1.7
45   * @author Sylvain Vieujot (latest modification by $Author: lu4242 $)
46   * @version $Revision: 783089 $ $Date: 2009-06-09 13:20:08 -0500 (Tue, 09 Jun 2009) $
47   */
48  public class MultipartRequestWrapper
49          extends HttpServletRequestWrapper
50  {
51      private static Log log = LogFactory.getLog(MultipartRequestWrapper.class);
52      public static final String UPLOADED_FILES_ATTRIBUTE = "org.apache.myfaces.uploadedFiles";
53      public static final String WWW_FORM_URLENCODED_TYPE = "application/x-www-form-urlencoded";
54  
55      HttpServletRequest request = null;
56      HashMap parametersMap = null;
57      ServletFileUpload fileUpload = null;
58      HashMap fileItems = null;
59      int maxFileSize;
60      int maxSize;
61      int thresholdSize;
62      String repositoryPath;
63      boolean cacheFileSizeErrors;
64  
65      public MultipartRequestWrapper(HttpServletRequest request,
66                                     int maxFileSize, int thresholdSize,
67                                     String repositoryPath){
68          super( request );
69          this.request = request;
70          this.maxFileSize = maxFileSize;
71          this.thresholdSize = thresholdSize;
72          this.repositoryPath = repositoryPath;
73          //Default values
74          this.maxSize = maxFileSize;
75          this.cacheFileSizeErrors = false;
76      }
77      
78      public MultipartRequestWrapper(HttpServletRequest request,
79              int maxFileSize, int thresholdSize,
80              String repositoryPath, int maxRequestSize, boolean cacheFileSizeErrors){
81          super( request );
82          this.request = request;
83          this.maxFileSize = maxFileSize;
84          this.maxSize = maxRequestSize;
85          this.thresholdSize = thresholdSize;
86          this.repositoryPath = repositoryPath;
87          this.cacheFileSizeErrors = cacheFileSizeErrors;
88      }
89  
90      private void parseRequest() {
91          if (cacheFileSizeErrors)
92          {
93              fileUpload = new ServletChacheFileSizeErrorsFileUpload();
94          }
95          else
96          {
97              fileUpload = new ServletFileUpload();
98          }
99          //fileUpload.setFileItemFactory(new DefaultFileItemFactory()); //USE DiskFileItemFactory
100         fileUpload.setSizeMax(maxSize);
101         fileUpload.setFileSizeMax(maxFileSize);
102 
103         //fileUpload.setSizeThreshold(thresholdSize); //Pass thresholdSize as param for DiskFileItemFactory
104 
105         //if(repositoryPath != null && repositoryPath.trim().length()>0)
106         //    fileUpload.setRepositoryPath(repositoryPath);
107         
108         if(repositoryPath != null && repositoryPath.trim().length()>0)
109         {
110             fileUpload.setFileItemFactory(
111                     new DiskFileItemFactory(thresholdSize,
112                             new File(repositoryPath)));
113         }
114         else
115         {
116             fileUpload.setFileItemFactory(
117                     new DiskFileItemFactory(thresholdSize,
118                             new File(System.getProperty("java.io.tmpdir"))));
119         }
120 
121         String charset = request.getCharacterEncoding();
122         fileUpload.setHeaderEncoding(charset);
123 
124 
125         List requestParameters = null;
126         
127         try
128         {
129             if (cacheFileSizeErrors)
130             {
131                 requestParameters = ((ServletChacheFileSizeErrorsFileUpload) fileUpload).
132                     parseRequestCatchingFileSizeErrors(request, fileUpload);
133             }
134             else
135             {
136                 requestParameters = fileUpload.parseRequest(request);
137             }
138         }
139         catch (FileUploadBase.FileSizeLimitExceededException e)
140         {
141             // Since commons-fileupload does not allow to continue processing files
142             // if this exception is thrown, we can't do anything else.
143             // So, the current request is rejected and we can't restore state, so 
144             // this request is dealt like a new request, but note that caching the params
145             // below it is possible to detect if the current request has been aborted
146             // or not.
147             // Note that if cacheFileSizeErrors is true, this is not thrown, so the request
148             // is not aborted unless other different error occur.
149             request.setAttribute(
150                     "org.apache.myfaces.custom.fileupload.exception","fileSizeLimitExceeded");
151             request.setAttribute("org.apache.myfaces.custom.fileupload.maxSize",
152                     new Integer((int)maxFileSize));
153             
154             if (log.isWarnEnabled())
155                 log.warn("FileSizeLimitExceededException while uploading file.", e);
156             
157             requestParameters = Collections.EMPTY_LIST;
158         }
159         catch (FileUploadBase.SizeLimitExceededException e)
160         {
161             // This exception is thrown when the max request size has been reached.
162             // In this case, the current request is rejected. The current 
163             // request is dealt like a new request, but note that caching the params below
164             // params it is possible to detect if the current request has been aborted
165             // or not.
166             request.setAttribute(
167                 "org.apache.myfaces.custom.fileupload.exception","sizeLimitExceeded");
168             request.setAttribute("org.apache.myfaces.custom.fileupload.maxSize",
169                 new Integer((int)maxSize));
170             
171             if (log.isWarnEnabled())
172                 log.warn("SizeLimitExceededException while uploading file.", e);
173             
174             requestParameters = Collections.EMPTY_LIST;
175         }
176         catch(FileUploadException fue)
177         {
178             if (log.isErrorEnabled())
179                 log.error("Exception while uploading file.", fue);
180             
181             requestParameters = Collections.EMPTY_LIST;
182         }        
183 
184         parametersMap = new HashMap( requestParameters.size() );
185         fileItems = new HashMap();
186 
187         for (Iterator iter = requestParameters.iterator(); iter.hasNext(); ){
188             FileItem fileItem = (FileItem) iter.next();
189 
190             if (fileItem.isFormField()) {
191                 String name = fileItem.getFieldName();
192 
193                 // The following code avoids commons-fileupload charset problem.
194                 // After fixing commons-fileupload, this code should be
195                 //
196                 //     String value = fileItem.getString();
197                 //
198                 String value = null;
199                 if ( charset == null) {
200                     value = fileItem.getString();
201                 } else {
202                     try {
203                         value = new String(fileItem.get(), charset);
204                     } catch (UnsupportedEncodingException e){
205                         value = fileItem.getString();
206                     }
207                 }
208 
209                 addTextParameter(name, value);
210             } else { // fileItem is a File
211                 if (fileItem.getName() != null) {
212                     fileItems.put(fileItem.getFieldName(), fileItem);
213                 }
214             }
215         }
216 
217         //Add the query string paramters
218         /* This code does only works if is true the assumption that query params
219          * are the same from start of the request. But it is possible
220          * use jsp:include and jsp:param to set query params after
221          * the request is parsed.
222         for (Iterator it = request.getParameterMap().entrySet().iterator(); it.hasNext(); )
223         {
224             Map.Entry entry = (Map.Entry)it.next();
225 
226             Object value = entry.getValue();
227 
228             if(value instanceof String[])
229             {
230                 String[] valuesArray = (String[])entry.getValue();
231                 for (int i = 0; i < valuesArray.length; i++)
232                 {
233                     addTextParameter((String)entry.getKey(), valuesArray[i]);
234                 }
235             }
236             else if(value instanceof String)
237             {
238                 String strValue = (String)entry.getValue();
239                 addTextParameter((String)entry.getKey(), strValue);
240             }
241             else if(value != null)
242                 throw new IllegalStateException("value of type : "+value.getClass()+" for key : "+
243                         entry.getKey()+" cannot be handled.");
244 
245         }
246         */
247     }
248 
249     private void addTextParameter(String name, String value){
250         if( ! parametersMap.containsKey( name ) ){
251             String[] valuesArray = {value};
252             parametersMap.put(name, valuesArray);
253         }else{
254             String[] storedValues = (String[])parametersMap.get( name );
255             int lengthSrc = storedValues.length;
256             String[] valuesArray = new String[lengthSrc+1];
257             System.arraycopy(storedValues, 0, valuesArray, 0, lengthSrc);
258             valuesArray[lengthSrc] = value;
259             parametersMap.put(name, valuesArray);
260         }
261     }
262 
263     public Enumeration getParameterNames() {
264         if( parametersMap == null ) parseRequest();
265 
266         //return Collections.enumeration( parametersMap.keySet() );
267         HashSet mergedNames = new HashSet(request.getParameterMap().keySet());
268         mergedNames.addAll(parametersMap.keySet());
269         
270         return Collections.enumeration( mergedNames );
271     }
272 
273     public String getParameter(String name) {
274         if( parametersMap == null ) parseRequest();
275 
276         String[] values = (String[])parametersMap.get( name );
277         //if( values == null )
278         //    return null;
279         //return values[0];
280         if (values != null)
281         {
282             return values[0];
283         }
284         else if (parametersMap.containsKey(name))
285         {
286             return null;
287         }
288         else
289         {
290             return request.getParameter(name);
291         }
292     }
293 
294     public String[] getParameterValues(String name) {
295         if( parametersMap == null ) parseRequest();
296 
297         //return (String[])parametersMap.get( name );
298         String[] values = (String[])parametersMap.get( name );
299         if (values != null)
300         {
301             return values;
302         }
303         else if (parametersMap.containsKey(name))
304         {
305             return null;
306         }
307         else
308         {
309             return request.getParameterValues(name);
310         }
311     }
312 
313     public Map getParameterMap() {
314         if( parametersMap == null ) parseRequest();
315 
316         //return parametersMap;
317         HashMap mergedMap = new HashMap(request.getParameterMap());
318         mergedMap.putAll(parametersMap);
319         return mergedMap;
320     }
321 
322     // Hook for the x:inputFileUpload tag.
323     public FileItem getFileItem(String fieldName) {
324         if( fileItems == null ) parseRequest();
325 
326         return (FileItem) fileItems.get( fieldName );
327     }
328 
329     /**
330      * Not used internally by MyFaces, but provides a way to handle the uploaded files
331      * out of MyFaces.
332      */
333     public Map getFileItems(){
334         if( fileItems == null ) parseRequest();
335         return fileItems;
336     }
337 
338 
339     public Object getAttribute(String string) {
340         if (string.equals(UPLOADED_FILES_ATTRIBUTE)) {
341             return getFileItems();
342         }
343         return super.getAttribute(string);
344     }
345     
346     public String getContentType()
347     {
348       return WWW_FORM_URLENCODED_TYPE;
349     }     
350 }