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