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.DiskFileUpload;
021    import org.apache.commons.fileupload.FileItem;
022    import org.apache.commons.fileupload.FileUploadException;
023    import org.apache.commons.logging.Log;
024    import org.apache.commons.logging.LogFactory;
025    import static org.apache.myfaces.tobago.TobagoConstants.FORM_ACCEPT_CHARSET;
026    
027    import javax.faces.FacesException;
028    import javax.servlet.http.HttpServletRequest;
029    import javax.servlet.http.HttpServletRequestWrapper;
030    import java.io.UnsupportedEncodingException;
031    import java.util.Collections;
032    import java.util.Enumeration;
033    import java.util.HashMap;
034    import java.util.Iterator;
035    import java.util.List;
036    import java.util.Map;
037    import java.util.Locale;
038    
039    public class TobagoMultipartFormdataRequest extends HttpServletRequestWrapper {
040    
041      private static final Log LOG
042          = LogFactory.getLog(TobagoMultipartFormdataRequest.class);
043    
044      public static final long ONE_KB = 1024;
045      public static final long ONE_MB = ONE_KB * ONE_KB;
046      public static final long ONE_GB = ONE_KB * ONE_MB;
047    
048      private Map parameters;
049    
050      private Map fileItems;
051    
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        String contentType = request.getContentType();
065        if (contentType == null
066            || !contentType.toLowerCase(Locale.ENGLISH).startsWith("multipart/form-data")) {
067          String errorText = "contentType is not multipart/form-data but '"
068              + contentType + "'";
069          LOG.error(errorText);
070          throw new FacesException(errorText);
071        } else {
072          parameters = new HashMap();
073          fileItems = new HashMap();
074          DiskFileUpload fileUpload = new DiskFileUpload();
075          fileUpload.setSizeMax(maxSize);
076          fileUpload.setRepositoryPath(repositoryPath);
077          List itemList;
078          try {
079            itemList = fileUpload.parseRequest(request);
080          } catch (FileUploadException e) {
081            //LOG.error(e);
082            throw new FacesException(e);
083          }
084          if (LOG.isDebugEnabled()) {
085            LOG.debug("parametercount = " + itemList.size());
086          }
087          Iterator items = itemList.iterator();
088          while (items.hasNext()) {
089            FileItem item = (FileItem) items.next();
090            String key = item.getFieldName();
091            if (LOG.isDebugEnabled()) {
092              String value = item.getString();
093              if (value.length() > 100) {
094                value = value.substring(0, 100) + " [...]";
095              }
096              LOG.debug(
097                  "Parameter : '" + key + "'='" + value + "' isFormField="
098                  + item.isFormField() + " contentType='" + item.getContentType() + "'");
099    
100            }
101            if (item.isFormField()) {
102              Object inStock = parameters.get(key);
103              if (inStock == null) {
104                String[] values;
105                try {
106                  // TODO: enable configuration of  'accept-charset'
107                  values = new String[] {item.getString(FORM_ACCEPT_CHARSET)};
108                } catch (UnsupportedEncodingException e) {
109                  LOG.error("Catched: " + e.getMessage(), e);
110                  values = new String[] {item.getString()};
111                }
112                parameters.put(key, values);
113              } else if (inStock instanceof String[]) { // double (or more) parameter
114                String[] oldValues = (String[]) inStock;
115                String[] values = new String[oldValues.length + 1];
116                int i = 0;
117                for (; i < oldValues.length; i++) {
118                  values[i] = oldValues[i];
119                }
120                try {
121                  // TODO: enable configuration of  'accept-charset'
122                  values[i] = item.getString(FORM_ACCEPT_CHARSET);
123                } catch (UnsupportedEncodingException e) {
124                  LOG.error("Catched: " + e.getMessage(), e);
125                  values[i] = item.getString();
126                }
127                parameters.put(key, values);
128              } else {
129                LOG.error(
130                    "Program error. Unsupported class: "
131                    + inStock.getClass().getName());
132              }
133            } else {
134              fileItems.put(key, item);
135            }
136          }
137        }
138      }
139    
140      public FileItem getFileItem(String key) {
141        if (fileItems != null) {
142          return (FileItem) fileItems.get(key);
143        }
144        return null;
145      }
146    
147      public String getParameter(String key) {
148        String parameter = null;
149        String[] values = (String[]) parameters.get(key);
150        if (values != null) {
151          parameter = values[0];
152        }
153        return parameter;
154      }
155    
156      public Enumeration getParameterNames() {
157        return Collections.enumeration(parameters.keySet());
158      }
159    
160      public String[] getParameterValues(String key) {
161        return (String[]) parameters.get(key);
162      }
163    
164      public Map getParameterMap() {
165        return parameters;
166      }
167    
168      public static long getMaxSize(String param) {
169        if (param != null) {
170          String number = param.toLowerCase(Locale.ENGLISH);
171          long factor = 1;
172          if (number.endsWith("g")) {
173            factor = ONE_GB;
174            number = number.substring(0, number.length() - 1);
175          } else if (number.endsWith("m")) {
176            factor = ONE_MB;
177            number = number.substring(0, number.length() - 1);
178          } else if (number.endsWith("k")) {
179            factor = ONE_KB;
180            number = number.substring(0, number.length() - 1);
181          }
182          try {
183            return Long.parseLong(number.trim()) * factor;
184          } catch (NumberFormatException e) {
185            LOG.error("Given max file size for "
186                + TobagoMultipartFormdataRequest.class.getName() + " " +param + " couldn't parsed to a number");
187          }
188        }
189        return ONE_MB;
190      }
191    }