View Javadoc

1   /*
2    * $Id: FileUploadInterceptorTest.java 722956 2008-12-03 16:23:43Z musachy $
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  
22  package org.apache.struts2.interceptor;
23  
24  import java.io.File;
25  import java.io.IOException;
26  import java.net.URI;
27  import java.net.URL;
28  import java.util.HashMap;
29  import java.util.List;
30  import java.util.Locale;
31  import java.util.Map;
32  
33  import javax.servlet.http.HttpServletRequest;
34  
35  import org.apache.struts2.ServletActionContext;
36  import org.apache.struts2.StrutsTestCase;
37  import org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest;
38  import org.apache.struts2.dispatcher.multipart.MultiPartRequest;
39  import org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper;
40  import org.apache.commons.fileupload.servlet.ServletFileUpload;
41  import org.springframework.mock.web.MockHttpServletRequest;
42  
43  import com.opensymphony.xwork2.util.ClassLoaderUtil;
44  import com.opensymphony.xwork2.ActionContext;
45  import com.opensymphony.xwork2.ActionSupport;
46  import com.opensymphony.xwork2.ValidationAwareSupport;
47  import com.opensymphony.xwork2.mock.MockActionInvocation;
48  
49  
50  /***
51   * Test case for FileUploadInterceptor.
52   */
53  public class FileUploadInterceptorTest extends StrutsTestCase {
54  
55      private FileUploadInterceptor interceptor;
56      private File tempDir;
57  
58      public void testAcceptFileWithEmptyAllowedTypesAndExtensions() throws Exception {
59          // when allowed type is empty
60          ValidationAwareSupport validation = new ValidationAwareSupport();
61          boolean ok = interceptor.acceptFile(null, new File(""), "filename", "text/plain", "inputName", validation, Locale.getDefault());
62  
63          assertTrue(ok);
64          assertTrue(validation.getFieldErrors().isEmpty());
65          assertFalse(validation.hasErrors());
66      }
67  
68      public void testAcceptFileWithoutEmptyTypes() throws Exception {
69          interceptor.setAllowedTypes("text/plain");
70  
71          // when file is of allowed types
72          ValidationAwareSupport validation = new ValidationAwareSupport();
73          boolean ok = interceptor.acceptFile(null, new File(""), "filename.txt", "text/plain", "inputName", validation, Locale.getDefault());
74  
75          assertTrue(ok);
76          assertTrue(validation.getFieldErrors().isEmpty());
77          assertFalse(validation.hasErrors());
78  
79          // when file is not of allowed types
80          validation = new ValidationAwareSupport();
81          boolean notOk = interceptor.acceptFile(null, new File(""), "filename.html", "text/html", "inputName", validation, Locale.getDefault());
82  
83          assertFalse(notOk);
84          assertFalse(validation.getFieldErrors().isEmpty());
85          assertTrue(validation.hasErrors());
86      }
87  
88      public void testAcceptFileWithoutEmptyExtensions() throws Exception {
89          interceptor.setAllowedExtensions(".txt");
90  
91          // when file is of allowed extensions
92          ValidationAwareSupport validation = new ValidationAwareSupport();
93          boolean ok = interceptor.acceptFile(null, new File(""), "filename.txt", "text/plain", "inputName", validation, Locale.getDefault());
94  
95          assertTrue(ok);
96          assertTrue(validation.getFieldErrors().isEmpty());
97          assertFalse(validation.hasErrors());
98  
99          // when file is not of allowed extensions
100         validation = new ValidationAwareSupport();
101         boolean notOk = interceptor.acceptFile(null, new File(""), "filename.html", "text/html", "inputName", validation, Locale.getDefault());
102 
103         assertFalse(notOk);
104         assertFalse(validation.getFieldErrors().isEmpty());
105         assertTrue(validation.hasErrors());
106 
107         //test with multiple extensions
108         interceptor.setAllowedExtensions(".txt,.lol");
109         validation = new ValidationAwareSupport();
110         ok = interceptor.acceptFile(null, new File(""), "filename.lol", "text/plain", "inputName", validation, Locale.getDefault());
111 
112         assertTrue(ok);
113         assertTrue(validation.getFieldErrors().isEmpty());
114         assertFalse(validation.hasErrors());
115     }
116 
117     public void testAcceptFileWithNoFile() throws Exception {
118         FileUploadInterceptor interceptor = new FileUploadInterceptor();
119         interceptor.setAllowedTypes("text/plain");
120 
121         // when file is not of allowed types
122         ValidationAwareSupport validation = new ValidationAwareSupport();
123         boolean notOk = interceptor.acceptFile(null, null, "filename.html", "text/html", "inputName", validation, Locale.getDefault());
124 
125         assertFalse(notOk);
126         assertFalse(validation.getFieldErrors().isEmpty());
127         assertTrue(validation.hasErrors());
128         List errors = (List) validation.getFieldErrors().get("inputName");
129         assertEquals(1, errors.size());
130         String msg = (String) errors.get(0);
131         assertTrue(msg.startsWith("Error uploading:"));
132         assertTrue(msg.indexOf("inputName") > 0);
133     }
134 
135     public void testAcceptFileWithMaxSize() throws Exception {
136         interceptor.setAllowedTypes("text/plain");
137         interceptor.setMaximumSize(new Long(10));
138 
139         // when file is not of allowed types
140         ValidationAwareSupport validation = new ValidationAwareSupport();
141 
142         URL url = ClassLoaderUtil.getResource("log4j.properties", FileUploadInterceptorTest.class);
143         File file = new File(new URI(url.toString()));
144         assertTrue("log4j.properties should be in src/test folder", file.exists());
145         boolean notOk = interceptor.acceptFile(null, file, "filename", "text/html", "inputName", validation, Locale.getDefault());
146 
147         assertFalse(notOk);
148         assertFalse(validation.getFieldErrors().isEmpty());
149         assertTrue(validation.hasErrors());
150         List errors = (List) validation.getFieldErrors().get("inputName");
151         assertEquals(1, errors.size());
152         String msg = (String) errors.get(0);
153         // the error message shoul contain at least this test
154         assertTrue(msg.startsWith("The file is to large to be uploaded"));
155         assertTrue(msg.indexOf("inputName") > 0);
156         assertTrue(msg.indexOf("log4j.properties") > 0);
157     }
158 
159     public void testNoMultipartRequest() throws Exception {
160         MyFileupAction action = new MyFileupAction();
161 
162         MockActionInvocation mai = new MockActionInvocation();
163         mai.setAction(action);
164         mai.setResultCode("NoMultipart");
165         mai.setInvocationContext(ActionContext.getContext());
166 
167         // if no multipart request it will bypass and execute it
168         assertEquals("NoMultipart", interceptor.intercept(mai));
169     }
170 
171     public void testInvalidContentTypeMultipartRequest() throws Exception {
172         MockHttpServletRequest req = new MockHttpServletRequest();
173 
174         req.setCharacterEncoding("text/html");
175         req.setContentType("text/xml"); // not a multipart contentype
176         req.addHeader("Content-type", "multipart/form-data");
177 
178         MyFileupAction action = new MyFileupAction();
179         MockActionInvocation mai = new MockActionInvocation();
180         mai.setAction(action);
181         mai.setResultCode("success");
182         mai.setInvocationContext(ActionContext.getContext());
183 
184         Map param = new HashMap();
185         ActionContext.getContext().setParameters(param);
186         ActionContext.getContext().put(ServletActionContext.HTTP_REQUEST, createMultipartRequest((HttpServletRequest) req, 2000));
187 
188         interceptor.intercept(mai);
189 
190         assertTrue(action.hasErrors());
191     }
192 
193     public void testNoContentMultipartRequest() throws Exception {
194         MockHttpServletRequest req = new MockHttpServletRequest();
195 
196         req.setCharacterEncoding("text/html");
197         req.setContentType("multipart/form-data; boundary=---1234");
198         req.setContent(null); // there is no content
199 
200         MyFileupAction action = new MyFileupAction();
201         MockActionInvocation mai = new MockActionInvocation();
202         mai.setAction(action);
203         mai.setResultCode("success");
204         mai.setInvocationContext(ActionContext.getContext());
205 
206         Map param = new HashMap();
207         ActionContext.getContext().setParameters(param);
208         ActionContext.getContext().put(ServletActionContext.HTTP_REQUEST, createMultipartRequest((HttpServletRequest) req, 2000));
209 
210         interceptor.intercept(mai);
211 
212         assertTrue(action.hasErrors());
213     }
214 
215     public void testSuccessUploadOfATextFileMultipartRequest() throws Exception {
216         MockHttpServletRequest req = new MockHttpServletRequest();
217         req.setCharacterEncoding("text/html");
218         req.setContentType("multipart/form-data; boundary=---1234");
219         req.addHeader("Content-type", "multipart/form-data");
220 
221         // inspired by the unit tests for jakarta commons fileupload
222         String content = ("-----1234\r\n" +
223                 "Content-Disposition: form-data; name=\"file\"; filename=\"deleteme.txt\"\r\n" +
224                 "Content-Type: text/html\r\n" +
225                 "\r\n" +
226                 "Unit test of FileUploadInterceptor" +
227                 "\r\n" +
228                 "-----1234--\r\n");
229         req.setContent(content.getBytes("US-ASCII"));
230 
231         MyFileupAction action = new MyFileupAction();
232 
233         MockActionInvocation mai = new MockActionInvocation();
234         mai.setAction(action);
235         mai.setResultCode("success");
236         mai.setInvocationContext(ActionContext.getContext());
237         Map<String, Object> param = new HashMap<String, Object>();
238         ActionContext.getContext().setParameters(param);
239         ActionContext.getContext().put(ServletActionContext.HTTP_REQUEST, createMultipartRequest((HttpServletRequest) req, 2000));
240 
241         interceptor.intercept(mai);
242 
243         assertTrue(!action.hasErrors());
244 
245         assertTrue(param.size() == 3);
246         File[] files = (File[]) param.get("file");
247         String[] fileContentTypes = (String[]) param.get("fileContentType");
248         String[] fileRealFilenames = (String[]) param.get("fileFileName");
249 
250         assertNotNull(files);
251         assertNotNull(fileContentTypes);
252         assertNotNull(fileRealFilenames);
253         assertTrue(files.length == 1);
254         assertTrue(fileContentTypes.length == 1);
255         assertTrue(fileRealFilenames.length == 1);
256         assertEquals("text/html", fileContentTypes[0]);
257         assertNotNull("deleteme.txt", fileRealFilenames[0]);
258     }
259 
260     /***
261      * tests whether with multiple files sent with the same name, the ones with forbiddenTypes (see
262      * FileUploadInterceptor.setAllowedTypes(...) ) are sorted out.
263      *
264      * @throws Exception
265      */
266     public void testMultipleAccept() throws Exception {
267         final String htmlContent = "<html><head></head><body>html content</body></html>";
268         final String plainContent = "plain content";
269         final String bondary = "simple boundary";
270         final String endline = "\r\n";
271 
272         MockHttpServletRequest req = new MockHttpServletRequest();
273         req.setCharacterEncoding("text/html");
274         req.setMethod("POST");
275         req.setContentType("multipart/form-data; boundary=" + bondary);
276         req.addHeader("Content-type", "multipart/form-data");
277         StringBuilder content = new StringBuilder(128);
278         content.append(encodeTextFile(bondary, endline, "file", "test.html", "text/plain", plainContent));
279         content.append(encodeTextFile(bondary, endline, "file", "test1.html", "text/html", htmlContent));
280         content.append(encodeTextFile(bondary, endline, "file", "test2.html", "text/html", htmlContent));
281         content.append(endline);
282         content.append(endline);
283         content.append(endline);
284         content.append("--");
285         content.append(bondary);
286         content.append("--");
287         content.append(endline);
288         req.setContent(content.toString().getBytes());
289 
290         assertTrue(ServletFileUpload.isMultipartContent(req));
291 
292         MyFileupAction action = new MyFileupAction();
293         MockActionInvocation mai = new MockActionInvocation();
294         mai.setAction(action);
295         mai.setResultCode("success");
296         mai.setInvocationContext(ActionContext.getContext());
297         Map<String, Object> param = new HashMap<String, Object>();
298         ActionContext.getContext().setParameters(param);
299         ActionContext.getContext().put(ServletActionContext.HTTP_REQUEST, createMultipartRequest(req, 2000));
300 
301         interceptor.setAllowedTypes("text/html");
302         interceptor.intercept(mai);
303 
304         assertEquals(3, param.size());
305         File[] files = (File[]) param.get("file");
306         String[] fileContentTypes = (String[]) param.get("fileContentType");
307         String[] fileRealFilenames = (String[]) param.get("fileFileName");
308 
309         assertNotNull(files);
310         assertNotNull(fileContentTypes);
311         assertNotNull(fileRealFilenames);
312         assertEquals("files accepted ", 2, files.length);
313         assertEquals(2, fileContentTypes.length);
314         assertEquals(2, fileRealFilenames.length);
315         assertEquals("text/html", fileContentTypes[0]);
316         assertNotNull("test1.html", fileRealFilenames[0]);
317     }
318 
319     private String encodeTextFile(String bondary, String endline, String name, String filename, String contentType, String content) {
320         final StringBuilder sb = new StringBuilder(64);
321         sb.append(endline);
322         sb.append("--");
323         sb.append(bondary);
324         sb.append(endline);
325         sb.append("Content-Disposition: form-data; name=\"");
326         sb.append(name);
327         sb.append("\"; filename=\"");
328         sb.append(filename);
329         sb.append(endline);
330         sb.append("Content-Type: ");
331         sb.append(contentType);
332         sb.append(endline);
333         sb.append(endline);
334         sb.append(content);
335 
336         return sb.toString();
337     }
338 
339     private MultiPartRequestWrapper createMultipartRequest(HttpServletRequest req, int maxsize) throws IOException {
340         JakartaMultiPartRequest jak = new JakartaMultiPartRequest();
341         jak.setMaxSize(String.valueOf(maxsize));
342         return new MultiPartRequestWrapper(jak, req, tempDir.getAbsolutePath());
343     }
344 
345     protected void setUp() throws Exception {
346         super.setUp();
347         interceptor = new FileUploadInterceptor();
348         tempDir = File.createTempFile("struts", "fileupload");
349         tempDir.delete();
350         tempDir.mkdirs();
351     }
352 
353     protected void tearDown() throws Exception {
354         tempDir.delete();
355         interceptor.destroy();
356         super.tearDown();
357     }
358 
359     private class MyFileupAction extends ActionSupport {
360 
361         private static final long serialVersionUID = 6255238895447968889L;
362 
363         // no methods
364     }
365 
366 
367 }