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  
20  package org.apache.myfaces.tobago.internal.webapp;
21  
22  import org.apache.commons.fileupload.FileItem;
23  import org.apache.commons.fileupload.FileUploadException;
24  import org.apache.commons.fileupload.disk.DiskFileItemFactory;
25  import org.apache.commons.fileupload.servlet.ServletFileUpload;
26  import org.slf4j.Logger;
27  import org.slf4j.LoggerFactory;
28  import org.apache.myfaces.tobago.internal.component.AbstractUIPage;
29  
30  import javax.faces.FacesException;
31  import javax.servlet.http.HttpServletRequest;
32  import javax.servlet.http.HttpServletRequestWrapper;
33  import java.io.File;
34  import java.io.UnsupportedEncodingException;
35  import java.util.Arrays;
36  import java.util.Collections;
37  import java.util.Enumeration;
38  import java.util.HashMap;
39  import java.util.List;
40  import java.util.Locale;
41  import java.util.Map;
42  
43  public class TobagoMultipartFormdataRequest extends HttpServletRequestWrapper {
44  
45    private static final Logger LOG = LoggerFactory.getLogger(TobagoMultipartFormdataRequest.class);
46  
47    public static final long ONE_KB = 1024;
48    public static final long ONE_MB = ONE_KB * ONE_KB;
49    public static final long ONE_GB = ONE_KB * ONE_MB;
50  
51    private Map<String, String[]> parameters;
52  
53    private Map<String, FileItem> fileItems;
54  
55    public TobagoMultipartFormdataRequest(HttpServletRequest request) {
56      this(request, System.getProperty("java.io.tmpdir"), ONE_MB);
57    }
58  
59    public TobagoMultipartFormdataRequest(HttpServletRequest request, String repositoryPath, long maxSize) {
60      super(request);
61      init(request, repositoryPath, maxSize);
62    }
63  
64    private void init(HttpServletRequest request, String repositoryPath, long maxSize) {
65      if (!ServletFileUpload.isMultipartContent(request)) {
66        String errorText = "contentType is not multipart/form-data but '" + request.getContentType() + "'";
67        LOG.error(errorText);
68        throw new FacesException(errorText);
69      } else {
70        parameters = new HashMap<String, String[]>();
71        fileItems = new HashMap<String, FileItem>();
72        DiskFileItemFactory factory = new DiskFileItemFactory();
73  
74        factory.setRepository(new File(repositoryPath));
75  
76        ServletFileUpload upload = new ServletFileUpload(factory);
77  
78        upload.setSizeMax(maxSize);
79  
80        if (upload.getHeaderEncoding() != null) {
81          // TODO: enable configuration of  'accept-charset'
82          upload.setHeaderEncoding(AbstractUIPage.FORM_ACCEPT_CHARSET);
83        }
84        List<FileItem> itemList;
85        try {
86          itemList = (List<FileItem>) upload.parseRequest(request);
87        } catch (FileUploadException e) {
88          //LOG.error(e);
89          throw new FacesException(e);
90        }
91        if (LOG.isDebugEnabled()) {
92          LOG.debug("parametercount = " + itemList.size() + " + " + request.getParameterMap().size());
93        }
94        for (FileItem item : itemList) {
95          String key = item.getFieldName();
96          if (LOG.isDebugEnabled()) {
97            String value = item.getString();
98            if (value.length() > 100) {
99              value = value.substring(0, 100) + " [...]";
100           }
101           LOG.debug("Parameter: '" + key + "'='" + value + "' isFormField=" + item.isFormField()
102               + " contentType='" + item.getContentType() + "'");
103         }
104         if (item.isFormField()) {
105           String newValue;
106           try {
107             // TODO: enable configuration of 'accept-charset'
108             newValue = item.getString(AbstractUIPage.FORM_ACCEPT_CHARSET);
109           } catch (UnsupportedEncodingException e) {
110             LOG.error("Caught: " + e.getMessage(), e);
111             newValue = item.getString();
112           }
113 
114           addParameter(key, newValue);
115         } else {
116           fileItems.put(key, item);
117         }
118       }
119 
120       // merging the GET parameters:
121       Enumeration e = request.getParameterNames();
122       while(e.hasMoreElements()) {
123         final String name = (String) e.nextElement();
124         final String[] newValues = request.getParameterValues(name);
125         if (LOG.isDebugEnabled()) {
126           LOG.debug("Parameter: '" + name + "'='" + Arrays.toString(newValues) + "' (GET)");
127         }
128         for (String newValue : newValues) {
129           addParameter(name, newValue);
130         }
131       }
132     }
133   }
134 
135   private void addParameter(String key, String newValue) {
136     final String[] inStock = parameters.get(key);
137     final String[] values;
138     if (inStock == null) {
139       values = new String[]{newValue};
140     } else {
141       values = new String[inStock.length + 1];
142       System.arraycopy(inStock, 0, values, 0, inStock.length);
143       values[inStock.length] = newValue;
144     }
145     parameters.put(key, values);
146   }
147 
148   public FileItem getFileItem(String key) {
149     if (fileItems != null) {
150       return fileItems.get(key);
151     }
152     return null;
153   }
154 
155   public String getParameter(String key) {
156     String parameter = null;
157     String[] values = (String[]) parameters.get(key);
158     if (values != null) {
159       parameter = values[0];
160     }
161     return parameter;
162   }
163 
164   public Enumeration getParameterNames() {
165     return Collections.enumeration(parameters.keySet());
166   }
167 
168   public String[] getParameterValues(String key) {
169     return (String[]) parameters.get(key);
170   }
171 
172   public Map getParameterMap() {
173     return parameters;
174   }
175 
176   public static long getMaxSize(String param) {
177     if (param != null) {
178       String number = param.toLowerCase(Locale.ENGLISH);
179       long factor = 1;
180       if (number.endsWith("g")) {
181         factor = ONE_GB;
182         number = number.substring(0, number.length() - 1);
183       } else if (number.endsWith("m")) {
184         factor = ONE_MB;
185         number = number.substring(0, number.length() - 1);
186       } else if (number.endsWith("k")) {
187         factor = ONE_KB;
188         number = number.substring(0, number.length() - 1);
189       }
190       try {
191         return Long.parseLong(number.trim()) * factor;
192       } catch (NumberFormatException e) {
193         LOG.error("Given max file size for "
194             + TobagoMultipartFormdataRequest.class.getName() + " " + param + " couldn't parsed to a number");
195       }
196     }
197     return ONE_MB;
198   }
199 }