001    package org.apache.myfaces.tobago.webapp;
002    
003    /*
004     * Licensed to the Apache Software Foundation (ASF) under one or more
005     * contributor license agreements.  See the NOTICE file distributed with
006     * this work for additional information regarding copyright ownership.
007     * The ASF licenses this file to You under the Apache License, Version 2.0
008     * (the "License"); you may not use this file except in compliance with
009     * the License.  You may obtain a copy of the License at
010     *
011     *      http://www.apache.org/licenses/LICENSE-2.0
012     *
013     * Unless required by applicable law or agreed to in writing, software
014     * distributed under the License is distributed on an "AS IS" BASIS,
015     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016     * See the License for the specific language governing permissions and
017     * limitations under the License.
018     */
019    
020    import org.apache.commons.fileupload.FileItem;
021    import org.apache.commons.fileupload.FileUploadException;
022    import org.apache.commons.fileupload.disk.DiskFileItemFactory;
023    import org.apache.commons.fileupload.servlet.ServletFileUpload;
024    import org.apache.commons.logging.Log;
025    import org.apache.commons.logging.LogFactory;
026    import static org.apache.myfaces.tobago.TobagoConstants.FORM_ACCEPT_CHARSET;
027    
028    import javax.faces.FacesException;
029    import javax.servlet.http.HttpServletRequest;
030    import javax.servlet.http.HttpServletRequestWrapper;
031    import java.io.File;
032    import java.io.UnsupportedEncodingException;
033    import java.util.Collections;
034    import java.util.Enumeration;
035    import java.util.HashMap;
036    import java.util.List;
037    import java.util.Locale;
038    import java.util.Map;
039    
040    public class TobagoMultipartFormdataRequest extends HttpServletRequestWrapper {
041    
042      private static final Log LOG
043          = LogFactory.getLog(TobagoMultipartFormdataRequest.class);
044    
045      public static final long ONE_KB = 1024;
046      public static final long ONE_MB = ONE_KB * ONE_KB;
047      public static final long ONE_GB = ONE_KB * ONE_MB;
048    
049      private Map parameters;
050    
051      private Map fileItems;
052    
053    
054      public TobagoMultipartFormdataRequest(HttpServletRequest request) {
055        this(request, System.getProperty("java.io.tmpdir"), ONE_MB);
056      }
057    
058      public TobagoMultipartFormdataRequest(HttpServletRequest request, String repositoryPath, long maxSize) {
059        super(request);
060        init(request, repositoryPath, maxSize);
061      }
062    
063      private void init(HttpServletRequest request, String repositoryPath, long maxSize) {
064        if (!ServletFileUpload.isMultipartContent(request)) {
065          String errorText = "contentType is not multipart/form-data but '"
066              + request.getContentType() + "'";
067          LOG.error(errorText);
068          throw new FacesException(errorText);
069        } else {
070          parameters = new HashMap();
071          fileItems = new HashMap();
072          DiskFileItemFactory factory = new DiskFileItemFactory();
073    
074          factory.setRepository(new File(repositoryPath));
075    
076          ServletFileUpload upload = new ServletFileUpload(factory);
077    
078          upload.setSizeMax(maxSize);
079    
080          if (upload.getHeaderEncoding() != null) {
081            // TODO: enable configuration of  'accept-charset'
082            upload.setHeaderEncoding(FORM_ACCEPT_CHARSET);
083          }
084          List<FileItem> itemList;
085          try {
086            itemList = (List<FileItem>) upload.parseRequest(request);
087          } catch (FileUploadException e) {
088            //LOG.error(e);
089            throw new FacesException(e);
090          }
091          if (LOG.isDebugEnabled()) {
092            LOG.debug("parametercount = " + itemList.size());
093          }
094          for (FileItem item : itemList) {
095            String key = item.getFieldName();
096            if (LOG.isDebugEnabled()) {
097              String value = item.getString();
098              if (value.length() > 100) {
099                value = value.substring(0, 100) + " [...]";
100              }
101              LOG.debug(
102                  "Parameter : '" + key + "'='" + value + "' isFormField="
103                      + item.isFormField() + " contentType='" + item.getContentType() + "'");
104    
105            }
106            if (item.isFormField()) {
107              Object inStock = parameters.get(key);
108              if (inStock == null) {
109                String[] values;
110                try {
111                  // TODO: enable configuration of  'accept-charset'
112                  values = new String[]{item.getString(FORM_ACCEPT_CHARSET)};
113                } catch (UnsupportedEncodingException e) {
114                  LOG.error("Caught: " + e.getMessage(), e);
115                  values = new String[]{item.getString()};
116                }
117                parameters.put(key, values);
118              } else if (inStock instanceof String[]) { // double (or more) parameter
119                String[] oldValues = (String[]) inStock;
120                String[] values = new String[oldValues.length + 1];
121                System.arraycopy(oldValues, 0, values, 0, oldValues.length);
122                try {
123                  // TODO: enable configuration of  'accept-charset'
124                  values[oldValues.length] = item.getString(FORM_ACCEPT_CHARSET);
125                } catch (UnsupportedEncodingException e) {
126                  LOG.error("Caught: " + e.getMessage(), e);
127                  values[oldValues.length] = item.getString();
128                }
129                parameters.put(key, values);
130              } else {
131                LOG.error(
132                    "Program error. Unsupported class: "
133                        + inStock.getClass().getName());
134              }
135            } else {
136              fileItems.put(key, item);
137            }
138          }
139        }
140      }
141    
142      public FileItem getFileItem(String key) {
143        if (fileItems != null) {
144          return (FileItem) fileItems.get(key);
145        }
146        return null;
147      }
148    
149      public String getParameter(String key) {
150        String parameter = null;
151        String[] values = (String[]) parameters.get(key);
152        if (values != null) {
153          parameter = values[0];
154        }
155        return parameter;
156      }
157    
158      public Enumeration getParameterNames() {
159        return Collections.enumeration(parameters.keySet());
160      }
161    
162      public String[] getParameterValues(String key) {
163        return (String[]) parameters.get(key);
164      }
165    
166      public Map getParameterMap() {
167        return parameters;
168      }
169    
170      public static long getMaxSize(String param) {
171        if (param != null) {
172          String number = param.toLowerCase(Locale.ENGLISH);
173          long factor = 1;
174          if (number.endsWith("g")) {
175            factor = ONE_GB;
176            number = number.substring(0, number.length() - 1);
177          } else if (number.endsWith("m")) {
178            factor = ONE_MB;
179            number = number.substring(0, number.length() - 1);
180          } else if (number.endsWith("k")) {
181            factor = ONE_KB;
182            number = number.substring(0, number.length() - 1);
183          }
184          try {
185            return Long.parseLong(number.trim()) * factor;
186          } catch (NumberFormatException e) {
187            LOG.error("Given max file size for "
188                + TobagoMultipartFormdataRequest.class.getName() + " " + param + " couldn't parsed to a number");
189          }
190        }
191        return ONE_MB;
192      }
193    }