001: /**
002: * Copyright 2006 Webmedia Group Ltd.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: **/package org.araneaframework.http.filter;
016:
017: import java.io.File;
018: import java.util.ArrayList;
019: import java.util.Collections;
020: import java.util.Enumeration;
021: import java.util.HashMap;
022: import java.util.Iterator;
023: import java.util.List;
024: import java.util.Map;
025: import javax.servlet.http.HttpServletRequest;
026: import javax.servlet.http.HttpServletRequestWrapper;
027: import org.apache.commons.fileupload.FileUploadBase;
028: import org.apache.commons.fileupload.FileUploadException;
029: import org.apache.commons.fileupload.disk.DiskFileItem;
030: import org.apache.commons.fileupload.disk.DiskFileItemFactory;
031: import org.apache.commons.fileupload.servlet.ServletFileUpload;
032: import org.apache.commons.fileupload.servlet.ServletRequestContext;
033: import org.apache.commons.logging.Log;
034: import org.apache.commons.logging.LogFactory;
035: import org.araneaframework.Environment;
036: import org.araneaframework.InputData;
037: import org.araneaframework.OutputData;
038: import org.araneaframework.Path;
039: import org.araneaframework.core.Assert;
040: import org.araneaframework.core.StandardEnvironment;
041: import org.araneaframework.framework.FileUploadContext;
042: import org.araneaframework.framework.core.BaseFilterService;
043: import org.araneaframework.http.FileUploadInputExtension;
044: import org.araneaframework.http.core.StandardFileUploadInputExtension;
045: import org.araneaframework.http.util.ServletUtil;
046:
047: /**
048: * This filter uses Commons FileUpload to parse the request and upload the <code>multipart/form-data</code> encoded files to a temporary
049: * directory.
050: *
051: * @author Jevgeni Kabanov (ekabanov <i>at</i> araneaframework <i>dot</i> org)
052: */
053: public class StandardFileUploadFilterService extends BaseFilterService
054: implements FileUploadContext {
055: private static final Log log = LogFactory
056: .getLog(StandardFileUploadFilterService.class);
057:
058: private static boolean commonsFileUploadPresent = true;
059:
060: static {
061: try {
062: Class
063: .forName("org.apache.commons.fileupload.servlet.ServletFileUpload");
064: } catch (ClassNotFoundException e) {
065: commonsFileUploadPresent = false;
066: }
067: }
068:
069: private String multipartEncoding;
070: private boolean useRequestEncoding = false;
071: private Integer maximumCachedSize = null;
072: private Long maximumSize = null;
073: private Long maximumRequestSize = null;
074: private String tempDirectory = null;
075:
076: /**
077: * Sets the character encoding that will be used to decode the <code>multipart/form-data</code> encoded strings. The default encoding is
078: * determined by Commons FileUpload.
079: */
080: public void setMultipartEncoding(String multipartEncoding) {
081: this .multipartEncoding = multipartEncoding;
082: }
083:
084: /**
085: * When set to "true" will use the request character encoding to parse the <code>multipart/form-data</code> encoded strings.
086: */
087: public void setUseRequestEncoding(boolean useRequestEncoding) {
088: this .useRequestEncoding = useRequestEncoding;
089: }
090:
091: /**
092: * Sets the maximum size of file that may be cached in memory.
093: */
094: public void setMaximumCachedSize(Integer maximumCachedSize) {
095: this .maximumCachedSize = maximumCachedSize;
096: }
097:
098: /**
099: * Sets the maximum size of file that may be uploaded to server.
100: */
101: public void setMaximumSize(Long maximumSize) {
102: this .maximumSize = maximumSize;
103: }
104:
105: /**
106: * Sets the maximum size of the request that may be sent to the server
107: */
108: public void setMaximumRequestSize(Long maximumRequestSize) {
109: this .maximumRequestSize = maximumRequestSize;
110: }
111:
112: /**
113: * Sets the temporary directory to use when uploading files.
114: */
115: public void setTempDirectory(String tempDirectory) {
116: this .tempDirectory = tempDirectory;
117: }
118:
119: protected void init() throws Exception {
120: if (!commonsFileUploadPresent) {
121: log
122: .warn("Jakarta Commons FileUpload not found! File uploading and multipart request handling will be disabled!");
123: }
124: super .init();
125: }
126:
127: protected Environment getChildEnvironment() {
128: return new StandardEnvironment(super .getChildEnvironment(),
129: FileUploadContext.class, this );
130: }
131:
132: protected void action(Path path, InputData input, OutputData output)
133: throws Exception {
134: HttpServletRequest request = ServletUtil.getRequest(input);
135:
136: if (commonsFileUploadPresent
137: && ServletFileUpload
138: .isMultipartContent(new ServletRequestContext(
139: request))) {
140: Map fileItems = new HashMap();
141: Map parameterLists = new HashMap();
142:
143: DiskFileItemFactory fileItemFactory = new DiskFileItemFactory();
144: // Set upload parameters
145: if (maximumCachedSize != null) {
146: fileItemFactory.setSizeThreshold(maximumCachedSize
147: .intValue());
148: }
149: if (tempDirectory != null) {
150: fileItemFactory.setRepository(new File(tempDirectory));
151: }
152:
153: // Create a new file upload handler
154: ServletFileUpload upload = new ServletFileUpload(
155: fileItemFactory);
156: if (maximumRequestSize != null) {
157: upload.setSizeMax(maximumRequestSize.longValue());
158: }
159:
160: if (useRequestEncoding) {
161: upload
162: .setHeaderEncoding(request
163: .getCharacterEncoding());
164: } else if (multipartEncoding != null) {
165: upload.setHeaderEncoding(multipartEncoding);
166: }
167:
168: // Parse the request
169: // FIXME: somehow parse the request so that all information except file
170: // upload data
171: // comes through when exception occurs.
172: List items = null;
173: Exception uploadException = null;
174: try {
175: items = upload.parseRequest(request);
176: } catch (FileUploadException e) {
177: if (log.isDebugEnabled()) {
178: log
179: .debug(
180: Assert.this ToString(this )
181: + ": exception occured parsing multipart request.",
182: e);
183: }
184: uploadException = e;
185: }
186: // Process the uploaded items
187: if (items != null) {
188: Iterator iter = items.iterator();
189: while (iter.hasNext()) {
190: DiskFileItem item = (DiskFileItem) iter.next();
191:
192: if (!item.isFormField()) {
193: if (maximumSize != null
194: && item.getSize() > maximumSize
195: .longValue()) {
196: uploadException = new FileUploadBase.FileSizeLimitExceededException(
197: "", item.getSize(), maximumSize
198: .longValue());
199: continue;
200: }
201: if (fileItems.containsKey(item.getFieldName())) {
202: log
203: .warn(item.getFieldName()
204: + " already has an associated file, overwriting...");
205: }
206: fileItems.put(item.getFieldName(), item);
207: } else {
208: List parameterValues = (List) parameterLists
209: .get(item.getFieldName());
210:
211: if (parameterValues == null) {
212: parameterValues = new ArrayList();
213: parameterLists.put(item.getFieldName(),
214: parameterValues);
215: }
216:
217: String encoding = item.getCharSet() != null ? item
218: .getCharSet()
219: : request.getCharacterEncoding();
220: parameterValues
221: .add(encoding != null ? item
222: .getString(encoding) : item
223: .getString());
224: }
225: }
226: }
227:
228: if (log.isDebugEnabled()) {
229: log.debug("Parsed multipart request, found '"
230: + fileItems.size() + "' file items and '"
231: + parameterLists.size()
232: + "' request parameters");
233: }
234: input.extend(FileUploadInputExtension.class,
235: new StandardFileUploadInputExtension(fileItems,
236: uploadException));
237:
238: request = new MultipartWrapper(request, parameterLists);
239: ServletUtil.setRequest(input, request);
240: }
241:
242: super .action(path, input, output);
243: }
244:
245: /**
246: *
247: * @author Jevgeni Kabanov (ekabanov <i>at</i> araneaframework <i>dot</i> org)
248: */
249: private static class MultipartWrapper extends
250: HttpServletRequestWrapper {
251: Map parameters = new HashMap();
252:
253: public MultipartWrapper(HttpServletRequest req,
254: Map parameterLists) throws Exception {
255: super (req);
256:
257: for (Iterator i = parameterLists.entrySet().iterator(); i
258: .hasNext();) {
259: Map.Entry entry = (Map.Entry) i.next();
260: List parameterList = (List) entry.getValue();
261:
262: parameters.put(entry.getKey(),
263: toStringArray(parameterList.toArray()));
264: }
265: }
266:
267: private String[] toStringArray(Object[] array) throws Exception {
268: String[] result = new String[array.length];
269:
270: for (int i = 0; i < array.length; i++) {
271: result[i] = (String) array[i];
272: }
273:
274: return result;
275: }
276:
277: public String getParameter(String arg0) {
278: String[] result = getParameterValues(arg0);
279:
280: if (result == null || result.length == 0) {
281: return null;
282: }
283: return result[0];
284: }
285:
286: public Map getParameterMap() {
287: return parameters;
288: }
289:
290: public Enumeration getParameterNames() {
291: return Collections.enumeration(parameters.keySet());
292: }
293:
294: public String[] getParameterValues(String arg0) {
295: return (String[]) parameters.get(arg0);
296: }
297: }
298:
299: public Long getFileSizeLimit() {
300: return maximumSize != null ? maximumSize : new Long(
301: new ServletFileUpload().getSizeMax());
302: }
303: }
|