View Javadoc

1   /**
2    * This file Copyright (c) 2003-2010 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
32   *
33   */
34  package info.magnolia.cms.filters;
35  
36  import info.magnolia.cms.beans.runtime.MultipartForm;
37  import info.magnolia.cms.core.Path;
38  import info.magnolia.context.MgnlContext;
39  
40  import java.io.File;
41  import java.io.IOException;
42  import java.io.UnsupportedEncodingException;
43  import java.util.Enumeration;
44  import java.util.Iterator;
45  import java.util.List;
46  import java.util.Map;
47  
48  import javax.servlet.FilterChain;
49  import javax.servlet.FilterConfig;
50  import javax.servlet.ServletException;
51  import javax.servlet.http.HttpServletRequest;
52  import javax.servlet.http.HttpServletRequestWrapper;
53  import javax.servlet.http.HttpServletResponse;
54  
55  import org.apache.commons.fileupload.FileItem;
56  import org.apache.commons.fileupload.FileUploadBase;
57  import org.apache.commons.fileupload.FileUploadException;
58  import org.apache.commons.fileupload.disk.DiskFileItemFactory;
59  import org.apache.commons.fileupload.servlet.ServletFileUpload;
60  import org.apache.commons.fileupload.servlet.ServletRequestContext;
61  import org.apache.commons.lang.ArrayUtils;
62  import org.apache.commons.lang.StringUtils;
63  import org.slf4j.Logger;
64  import org.slf4j.LoggerFactory;
65  
66  
67  /**
68   * A <code>Filter</code> that determines if a <code>HttpServletRequest</code> contains multipart content and if so
69   * parses it into a request attribute for further processing. This implementation uses jakarta commons-fileupload for
70   * parsing multipart requests. Maximum file size can be configured using the "maxFileSize" init parameter, defaulting to
71   * 2 GB.
72   * @author Andreas Brenk
73   * @author Fabrizio Giustina
74   * @version $Id: MultipartRequestFilter.java 32667 2010-03-13 00:37:06Z gjoseph $
75   */
76  public class MultipartRequestFilter extends AbstractMgnlFilter {
77      private static final Logger log = LoggerFactory.getLogger(MultipartRequestFilter.class);
78  
79      /**
80       * Default max file upload size (2 GB).
81       */
82      private static final int DEFAULT_MAX_FILE_SIZE = 2000000000; // 2GB
83  
84      /**
85       * Config parameter name for max file size.
86       */
87      private static final String PARAM_MAX_FILE_SIZE = "maxFileSize";
88  
89      /**
90       * The maximum size a file upload may have.
91       */
92      private long maxFileSize = DEFAULT_MAX_FILE_SIZE;
93  
94      /**
95       * The directory for temporary storage of uploaded files.
96       */
97      private File tempDir;
98  
99      /**
100      * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
101      */
102     public void init(FilterConfig config) throws ServletException {
103         super.init(config);
104         String maxFileSize = config.getInitParameter(PARAM_MAX_FILE_SIZE);
105         if (maxFileSize != null) {
106             this.maxFileSize = Long.parseLong(maxFileSize);
107         }
108 
109         this.tempDir = new File(Path.getTempDirectoryPath());
110     }
111 
112     /**
113      * Determine if the request has multipart content and if so parse it into a <code>MultipartForm</code> and store
114      * it as a request attribute.
115      */
116     public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
117         throws IOException, ServletException {
118 
119         boolean isMultipartContent = FileUploadBase.isMultipartContent(new ServletRequestContext(request));
120         if (isMultipartContent) {
121             MultipartForm mpf = parseRequest(request);
122             // wrap the request
123             request = new MultipartRequestWrapper(request, mpf);
124             MgnlContext.push(request, response);
125         }
126         chain.doFilter(request, response);
127         if(isMultipartContent){
128             MgnlContext.pop();
129         }
130     }
131 
132     /**
133      * Parse the request and store it as a request attribute.
134      */
135     private MultipartForm parseRequest(HttpServletRequest request) throws IOException, ServletException {
136         MultipartForm form = new MultipartForm();
137 
138         ServletFileUpload upload = newServletFileUpload();
139 
140         final List fileItems;
141         try {
142             fileItems = upload.parseRequest(request);
143         } catch (FileUploadException e) {
144             throw new ServletException("Could not upload files:" + e.getMessage(), e);
145         }
146 
147         for (Iterator fileItemIterator = fileItems.iterator(); fileItemIterator.hasNext();) {
148             FileItem item = (FileItem) fileItemIterator.next();
149             if (item.isFormField()) {
150                 addField(request, item, form);
151             }
152             else {
153                 addFile(item, form);
154             }
155         }
156 
157         request.setAttribute(MultipartForm.REQUEST_ATTRIBUTE_NAME, form);
158         return form;
159     }
160 
161     /**
162      * Create a new <code>DiskFileUpload</code>.
163      */
164     private ServletFileUpload newServletFileUpload() {
165         ServletFileUpload upload = new ServletFileUpload();
166         upload.setSizeMax(this.maxFileSize);
167         DiskFileItemFactory fif = new DiskFileItemFactory();
168         fif.setRepository(Path.getTempDirectory());
169         upload.setFileItemFactory(fif);
170 
171         return upload;
172     }
173 
174     /**
175      * Add the <code>FileItem</code> as a paramter into the <code>MultipartForm</code>.
176      */
177     private void addField(HttpServletRequest request, FileItem item, MultipartForm form) {
178         String name = item.getFieldName();
179 
180         String value;
181         try {
182             String encoding = StringUtils.defaultString(request.getCharacterEncoding(), "UTF-8");
183             value = item.getString(encoding);
184         }
185         catch (UnsupportedEncodingException ex) {
186             value = item.getString();
187         }
188 
189         form.addParameter(name, value);
190 
191         String[] values = form.getParameterValues(name);
192         if (values == null) {
193             form.addparameterValues(name, new String[]{value});
194         }
195         else {
196             form.addparameterValues(name, (String[]) ArrayUtils.add(values, value));
197         }
198     }
199 
200     /**
201      * Add the <code>FileItem</code> as a document into the <code>MultipartForm</code>.
202      */
203     private void addFile(FileItem item, MultipartForm form) throws IOException {
204         String atomName = item.getFieldName();
205         String fileName = item.getName();
206         String type = item.getContentType();
207         File file = File.createTempFile(atomName, null, this.tempDir);
208         try {
209             item.write(file);
210         } catch (Exception e) {
211             log.error("Could not write uploaded file: " + e.getMessage(), e);
212             throw new IOException("Could not write uploaded file: " + e.getMessage());
213         }
214 
215         form.addDocument(atomName, fileName, type, file);
216     }
217 
218     static class MultipartRequestWrapper extends HttpServletRequestWrapper {
219         private final MultipartForm form;
220 
221         public MultipartRequestWrapper(HttpServletRequest request, MultipartForm form) {
222             super(request);
223             this.form = form;
224         }
225 
226         /**
227          * {@inheritDoc}
228          */
229         public String getParameter(String name) {
230             String value = form.getParameter(name);
231             log.debug("getParameter: {}={}", name, value);
232             return value;
233         }
234 
235         /**
236          * {@inheritDoc}
237          */
238         public Map getParameterMap() {
239             return form.getParameters();
240         }
241 
242         /**
243          * {@inheritDoc}
244          */
245         public Enumeration getParameterNames() {
246             return form.getParameterNames();
247         }
248 
249         /**
250          * {@inheritDoc}
251          */
252         public String[] getParameterValues(String name) {
253             String[] value = form.getParameterValues(name);
254             log.debug("getParameterValues: {}={}", name, value);
255             return value;
256         }
257 
258     }
259 }