001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied. See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019
020 package org.apache.myfaces.tobago.webapp;
021
022 import org.apache.commons.fileupload.FileItem;
023 import org.apache.commons.fileupload.FileUploadException;
024 import org.apache.commons.fileupload.disk.DiskFileItemFactory;
025 import org.apache.commons.fileupload.servlet.ServletFileUpload;
026 import org.apache.commons.logging.Log;
027 import org.apache.commons.logging.LogFactory;
028
029 import javax.faces.FacesException;
030 import javax.servlet.http.HttpServletRequest;
031 import javax.servlet.http.HttpServletRequestWrapper;
032 import java.io.File;
033 import java.io.UnsupportedEncodingException;
034 import java.util.Arrays;
035 import java.util.Collections;
036 import java.util.Enumeration;
037 import java.util.HashMap;
038 import java.util.List;
039 import java.util.Locale;
040 import java.util.Map;
041
042 import static org.apache.myfaces.tobago.TobagoConstants.FORM_ACCEPT_CHARSET;
043
044 public class TobagoMultipartFormdataRequest extends HttpServletRequestWrapper {
045
046 private static final Log LOG = LogFactory.getLog(TobagoMultipartFormdataRequest.class);
047
048 public static final long ONE_KB = 1024;
049 public static final long ONE_MB = ONE_KB * ONE_KB;
050 public static final long ONE_GB = ONE_KB * ONE_MB;
051
052 private Map<String, String[]> parameters;
053
054 private Map<String, FileItem> fileItems;
055
056 public TobagoMultipartFormdataRequest(HttpServletRequest request) {
057 this(request, System.getProperty("java.io.tmpdir"), ONE_MB);
058 }
059
060 public TobagoMultipartFormdataRequest(HttpServletRequest request, String repositoryPath, long maxSize) {
061 super(request);
062 init(request, repositoryPath, maxSize);
063 }
064
065 private void init(HttpServletRequest request, String repositoryPath, long maxSize) {
066 if (!ServletFileUpload.isMultipartContent(request)) {
067 String errorText = "contentType is not multipart/form-data but '" + request.getContentType() + "'";
068 LOG.error(errorText);
069 throw new FacesException(errorText);
070 } else {
071 parameters = new HashMap<String, String[]>();
072 fileItems = new HashMap<String, FileItem>();
073 DiskFileItemFactory factory = new DiskFileItemFactory();
074
075 factory.setRepository(new File(repositoryPath));
076
077 ServletFileUpload upload = new ServletFileUpload(factory);
078
079 upload.setSizeMax(maxSize);
080
081 if (upload.getHeaderEncoding() != null) {
082 // TODO: enable configuration of 'accept-charset'
083 upload.setHeaderEncoding(FORM_ACCEPT_CHARSET);
084 }
085 List<FileItem> itemList;
086 try {
087 itemList = (List<FileItem>) upload.parseRequest(request);
088 } catch (FileUploadException e) {
089 //LOG.error(e);
090 throw new FacesException(e);
091 }
092 if (LOG.isDebugEnabled()) {
093 LOG.debug("parametercount = " + itemList.size() + " + " + request.getParameterMap().size());
094 }
095 for (FileItem item : itemList) {
096 String key = item.getFieldName();
097 if (LOG.isDebugEnabled()) {
098 String value = item.getString();
099 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(FORM_ACCEPT_CHARSET);
110 } catch (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 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 (String newValue : newValues) {
130 addParameter(name, newValue);
131 }
132 }
133 }
134 }
135
136 private void addParameter(String key, 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(String key) {
150 if (fileItems != null) {
151 return fileItems.get(key);
152 }
153 return null;
154 }
155
156 public String getParameter(String key) {
157 String parameter = null;
158 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(String key) {
170 return (String[]) parameters.get(key);
171 }
172
173 public Map getParameterMap() {
174 return parameters;
175 }
176
177 public static long getMaxSize(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 (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 }