View Javadoc

1   /*
2    * $Id: JakartaMultiPartRequest.java 559304 2007-07-25 03:39:12Z jholmes $
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  package org.apache.struts2.dispatcher.multipart;
22  
23  import java.io.File;
24  import java.io.IOException;
25  import java.io.InputStream;
26  import java.util.ArrayList;
27  import java.util.Collections;
28  import java.util.Enumeration;
29  import java.util.HashMap;
30  import java.util.List;
31  import java.util.Map;
32  
33  import javax.servlet.http.HttpServletRequest;
34  
35  import org.apache.commons.fileupload.FileItem;
36  import org.apache.commons.fileupload.FileUploadException;
37  import org.apache.commons.fileupload.RequestContext;
38  import org.apache.commons.fileupload.disk.DiskFileItem;
39  import org.apache.commons.fileupload.disk.DiskFileItemFactory;
40  import org.apache.commons.fileupload.servlet.ServletFileUpload;
41  import org.apache.commons.logging.Log;
42  import org.apache.commons.logging.LogFactory;
43  import org.apache.struts2.StrutsConstants;
44  
45  import com.opensymphony.xwork2.inject.Inject;
46  
47  /***
48   * Multipart form data request adapter for Jakarta Commons Fileupload package.
49   *
50   */
51  public class JakartaMultiPartRequest implements MultiPartRequest {
52      
53      static final Log log = LogFactory.getLog(MultiPartRequest.class);
54      
55      // maps parameter name -> List of FileItem objects
56      private Map<String,List<FileItem>> files = new HashMap<String,List<FileItem>>();
57      // maps parameter name -> List of param values
58      private Map<String,List<String>> params = new HashMap<String,List<String>>();
59      // any errors while processing this request
60      private List<String> errors = new ArrayList<String>();
61      
62      private long maxSize;
63      
64      @Inject(StrutsConstants.STRUTS_MULTIPART_MAXSIZE)
65      public void setMaxSize(String maxSize) {
66          this.maxSize = Long.parseLong(maxSize);
67      }
68  
69      /***
70       * Creates a new request wrapper to handle multi-part data using methods adapted from Jason Pell's
71       * multipart classes (see class description).
72       *
73       * @param saveDir        the directory to save off the file
74       * @param servletRequest the request containing the multipart
75       * @throws java.io.IOException  is thrown if encoding fails.
76       */
77      public void parse(HttpServletRequest servletRequest, String saveDir)
78              throws IOException {
79          DiskFileItemFactory fac = new DiskFileItemFactory();
80          // Make sure that the data is written to file
81          fac.setSizeThreshold(0);
82          if (saveDir != null) {
83              fac.setRepository(new File(saveDir));
84          }
85  
86          // Parse the request
87          try {
88              ServletFileUpload upload = new ServletFileUpload(fac);
89              upload.setSizeMax(maxSize);
90              List items = upload.parseRequest(createRequestContext(servletRequest));
91  
92              for (Object item1 : items) {
93                  FileItem item = (FileItem) item1;
94                  if (log.isDebugEnabled()) log.debug("Found item " + item.getFieldName());
95                  if (item.isFormField()) {
96                      log.debug("Item is a normal form field");
97                      List<String> values;
98                      if (params.get(item.getFieldName()) != null) {
99                          values = params.get(item.getFieldName());
100                     } else {
101                         values = new ArrayList<String>();
102                     }
103 
104                     // note: see http://jira.opensymphony.com/browse/WW-633
105                     // basically, in some cases the charset may be null, so
106                     // we're just going to try to "other" method (no idea if this
107                     // will work)
108                     String charset = servletRequest.getCharacterEncoding();
109                     if (charset != null) {
110                         values.add(item.getString(charset));
111                     } else {
112                         values.add(item.getString());
113                     }
114                     params.put(item.getFieldName(), values);
115                 } else {
116                     log.debug("Item is a file upload");
117 
118                     // Skip file uploads that don't have a file name - meaning that no file was selected.
119                     if (item.getName() == null || item.getName().trim().length() < 1) {
120                         log.debug("No file has been uploaded for the field: " + item.getFieldName());
121                         continue;
122                     }
123 
124                     List<FileItem> values;
125                     if (files.get(item.getFieldName()) != null) {
126                         values = files.get(item.getFieldName());
127                     } else {
128                         values = new ArrayList<FileItem>();
129                     }
130 
131                     values.add(item);
132                     files.put(item.getFieldName(), values);
133                 }
134             }
135         } catch (FileUploadException e) {
136             log.error(e);
137             errors.add(e.getMessage());
138         }
139     }
140 
141     /* (non-Javadoc)
142      * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getFileParameterNames()
143      */
144     public Enumeration<String> getFileParameterNames() {
145         return Collections.enumeration(files.keySet());
146     }
147 
148     /* (non-Javadoc)
149      * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getContentType(java.lang.String)
150      */
151     public String[] getContentType(String fieldName) {
152         List items = (List) files.get(fieldName);
153 
154         if (items == null) {
155             return null;
156         }
157 
158         List<String> contentTypes = new ArrayList<String>(items.size());
159         for (int i = 0; i < items.size(); i++) {
160             FileItem fileItem = (FileItem) items.get(i);
161             contentTypes.add(fileItem.getContentType());
162         }
163 
164         return (String[]) contentTypes.toArray(new String[contentTypes.size()]);
165     }
166 
167     /* (non-Javadoc)
168      * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getFile(java.lang.String)
169      */
170     public File[] getFile(String fieldName) {
171         List items = (List) files.get(fieldName);
172 
173         if (items == null) {
174             return null;
175         }
176 
177         List<File> fileList = new ArrayList<File>(items.size());
178         for (int i = 0; i < items.size(); i++) {
179             DiskFileItem fileItem = (DiskFileItem) items.get(i);
180             fileList.add(fileItem.getStoreLocation());
181         }
182 
183         return (File[]) fileList.toArray(new File[fileList.size()]);
184     }
185 
186     /* (non-Javadoc)
187      * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getFileNames(java.lang.String)
188      */
189     public String[] getFileNames(String fieldName) {
190         List<FileItem> items = files.get(fieldName);
191 
192         if (items == null) {
193             return null;
194         }
195 
196         List<String> fileNames = new ArrayList<String>(items.size());
197         for (int i = 0; i < items.size(); i++) {
198             DiskFileItem fileItem = (DiskFileItem) items.get(i);
199             fileNames.add(getCanonicalName(fileItem.getName()));
200         }
201 
202         return (String[]) fileNames.toArray(new String[fileNames.size()]);
203     }
204 
205     /* (non-Javadoc)
206      * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getFilesystemName(java.lang.String)
207      */
208     public String[] getFilesystemName(String fieldName) {
209         List items = (List) files.get(fieldName);
210 
211         if (items == null) {
212             return null;
213         }
214 
215         List<String> fileNames = new ArrayList<String>(items.size());
216         for (int i = 0; i < items.size(); i++) {
217             DiskFileItem fileItem = (DiskFileItem) items.get(i);
218             fileNames.add(fileItem.getStoreLocation().getName());
219         }
220 
221         return (String[]) fileNames.toArray(new String[fileNames.size()]);
222     }
223 
224     /* (non-Javadoc)
225      * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getParameter(java.lang.String)
226      */
227     public String getParameter(String name) {
228         List v = (List) params.get(name);
229         if (v != null && v.size() > 0) {
230             return (String) v.get(0);
231         }
232 
233         return null;
234     }
235 
236     /* (non-Javadoc)
237      * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getParameterNames()
238      */
239     public Enumeration<String> getParameterNames() {
240         return Collections.enumeration(params.keySet());
241     }
242 
243     /* (non-Javadoc)
244      * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getParameterValues(java.lang.String)
245      */
246     public String[] getParameterValues(String name) {
247         List<String> v = params.get(name);
248         if (v != null && v.size() > 0) {
249             return (String[]) v.toArray(new String[v.size()]);
250         }
251 
252         return null;
253     }
254 
255     /* (non-Javadoc)
256      * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getErrors()
257      */
258     public List getErrors() {
259         return errors;
260     }
261 
262     /***
263      * Returns the canonical name of the given file.
264      *
265      * @param filename  the given file
266      * @return the canonical name of the given file
267      */
268     private String getCanonicalName(String filename) {
269         int forwardSlash = filename.lastIndexOf("/");
270         int backwardSlash = filename.lastIndexOf("//");
271         if (forwardSlash != -1 && forwardSlash > backwardSlash) {
272             filename = filename.substring(forwardSlash + 1, filename.length());
273         } else if (backwardSlash != -1 && backwardSlash >= forwardSlash) {
274             filename = filename.substring(backwardSlash + 1, filename.length());
275         }
276 
277         return filename;
278     }
279 
280     /***
281      * Creates a RequestContext needed by Jakarta Commons Upload.
282      *
283      * @param req  the request.
284      * @return a new request context.
285      */
286     private RequestContext createRequestContext(final HttpServletRequest req) {
287         return new RequestContext() {
288             public String getCharacterEncoding() {
289                 return req.getCharacterEncoding();
290             }
291 
292             public String getContentType() {
293                 return req.getContentType();
294             }
295 
296             public int getContentLength() {
297                 return req.getContentLength();
298             }
299 
300             public InputStream getInputStream() throws IOException {
301                 return req.getInputStream();
302             }
303         };
304     }
305 
306 }