1 package gboat2.base.plugin.struts.interceptor;
2
3 import gboat2.base.bridge.GboatAppContext;
4 import gboat2.base.bridge.util.FileUtil;
5 import gboat2.base.bridge.util.security.MD5Util;
6
7 import java.io.File;
8 import java.io.IOException;
9 import java.util.ArrayList;
10 import java.util.Enumeration;
11 import java.util.List;
12 import java.util.Map;
13
14 import javax.servlet.ServletContext;
15 import javax.servlet.ServletRequest;
16 import javax.servlet.http.HttpServletRequest;
17 import javax.servlet.http.HttpServletRequestWrapper;
18 import javax.servlet.http.HttpServletResponse;
19
20 import org.apache.commons.lang3.StringUtils;
21 import org.apache.struts2.StrutsConstants;
22 import org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper;
23 import org.apache.struts2.interceptor.FileUploadInterceptor;
24
25 import com.opensymphony.xwork2.ActionContext;
26 import com.opensymphony.xwork2.ActionInvocation;
27 import com.opensymphony.xwork2.ValidationAware;
28 import com.opensymphony.xwork2.inject.Inject;
29 import com.opensymphony.xwork2.util.logging.Logger;
30 import com.opensymphony.xwork2.util.logging.LoggerFactory;
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63 public class GboatFileUploadInterceptor extends FileUploadInterceptor {
64
65 private static final long serialVersionUID = 1L;
66
67 private static final Logger logger = LoggerFactory.getLogger(GboatFileUploadInterceptor.class);
68
69
70
71 private static final String UPLOAD_DATA = "upload_data";
72
73
74 private static final String ASK_BREAKPOINT = "ask_breakpoint";
75
76
77 private static final String CURRENT_CHUNK = "chunk";
78
79
80 private static final String CHUNKS = "chunks";
81
82
83 private static final String RESUMABLE_SIZE = "resumable_size";
84
85
86 private static final String RESUMABLE_MODIFICATION_DATE = "resumable_modificationDate";
87
88
89 private static final String RESUMABLE_FILENAME = "resumable_filename";
90
91
92 private static final String RESUMABLE_UPLOAD = "ResumableUpload";
93
94
95
96
97
98
99 private String multipartSaveDir;
100
101 public String getMultipartSaveDir() {
102 return multipartSaveDir;
103 }
104
105 private ServletContext servletContext;
106
107 @Inject
108 public void setServletContext(ServletContext context) {
109 servletContext = context;
110 }
111
112 @Override
113 public void setAllowedExtensions(String allowedExtensions) {
114
115 String extraExtensions = servletContext.getInitParameter("fileupload.extra.allowed.extensions");
116 if (StringUtils.isNotEmpty(extraExtensions)) {
117 allowedExtensions = extraExtensions + "," + allowedExtensions;
118 }
119 super.setAllowedExtensions(allowedExtensions);
120 }
121
122 @Inject(StrutsConstants.STRUTS_MULTIPART_SAVEDIR)
123 public void setMultipartSaveDir(String multipartSaveDir) {
124 this.multipartSaveDir = multipartSaveDir;
125 }
126
127 @Override
128 public String intercept(ActionInvocation invocation) throws Exception {
129 HttpServletRequest request = GboatAppContext.getRequest();
130
131 MultiPartRequestWrapper multiWrapper = null;
132 if(request instanceof MultiPartRequestWrapper) {
133 multiWrapper = (MultiPartRequestWrapper) request;
134 } else {
135
136 ServletRequest req = request;
137 while (req instanceof HttpServletRequestWrapper) {
138 req = ((HttpServletRequestWrapper)req).getRequest();
139 if(req instanceof MultiPartRequestWrapper) {
140 multiWrapper = (MultiPartRequestWrapper) req;
141 break;
142 }
143 }
144 }
145
146
147 String resumable_upload = request.getHeader(RESUMABLE_UPLOAD);
148 if (StringUtils.isEmpty(resumable_upload) && (multiWrapper == null)) {
149 if (logger.isDebugEnabled()) {
150 logger.debug("No MultiPartRequestWrapper, Gboat2FileUploadInterceptor ignore.");
151 }
152 return invocation.invoke();
153 }
154
155
156 HttpServletResponse response = GboatAppContext.getResponse();
157 ServletContext servletContext = GboatAppContext.getServletContext();
158 if (!StringUtils.isEmpty(resumable_upload)) {
159
160 if (ASK_BREAKPOINT.equals(resumable_upload)) {
161 File file = new File(getBreak_Point_TempDir(servletContext) + File.separator + getFullMD5FileName(request));
162 GboatAppContext.output(file.exists() ? file.length() : 0);
163 return null;
164 }
165 }
166 List<File> filesToCleanup = new ArrayList<File>(1);
167
168
169 ValidationAware validation = null;
170
171 Object action = invocation.getAction();
172
173 if (action instanceof ValidationAware) {
174 validation = (ValidationAware) action;
175 }
176
177 if (multiWrapper.hasErrors()) {
178 for (String error : multiWrapper.getErrors()) {
179 if (validation != null) {
180 validation.addActionError(error);
181 }
182 logger.warn(error);
183 }
184 }
185
186
187 Enumeration<?> fileParameterNames = multiWrapper.getFileParameterNames();
188 while (fileParameterNames != null && fileParameterNames.hasMoreElements()) {
189
190 String inputName = (String) fileParameterNames.nextElement();
191
192
193 String[] contentType = multiWrapper.getContentTypes(inputName);
194
195 if (isNonEmpty(contentType)) {
196
197 String[] fileName = multiWrapper.getFileNames(inputName);
198
199 if (isNonEmpty(fileName)) {
200
201 File[] files = multiWrapper.getFiles(inputName);
202 if (files != null && files.length > 0) {
203 List<File> acceptedFiles = new ArrayList<File>(files.length);
204 List<String> acceptedContentTypes = new ArrayList<String>(files.length);
205 List<String> acceptedFileNames = new ArrayList<String>(files.length);
206 String contentTypeName = inputName + "ContentType";
207 String fileNameName = inputName + "FileName";
208
209 for (int index = 0; index < files.length; index++) {
210 if (acceptFile(action, files[index], fileName[index], contentType[index], inputName, validation)) {
211 acceptedFiles.add(files[index]);
212 acceptedContentTypes.add(contentType[index]);
213 acceptedFileNames.add(fileName[index]);
214 }
215 }
216
217 if (!acceptedFiles.isEmpty()) {
218 Map<String, Object> params = ActionContext.getContext().getParameters();
219
220 params.put(inputName, acceptedFiles.toArray(new File[acceptedFiles.size()]));
221 params.put(contentTypeName, acceptedContentTypes.toArray(new String[acceptedContentTypes.size()]));
222 params.put(fileNameName, acceptedFileNames.toArray(new String[acceptedFileNames.size()]));
223
224
225 if (!StringUtils.isEmpty(resumable_upload)) {
226
227 String chunks = request.getParameter(CHUNKS);
228
229 String currentChunk = request.getParameter(CURRENT_CHUNK);
230
231 if (UPLOAD_DATA.equals(resumable_upload)) {
232 File file = new File(getBreak_Point_TempDir(servletContext) + File.separator
233 + getFullMD5FileName(request));
234 File appendedFile = acceptedFiles.get(0);
235 boolean isLastChunck = Integer.valueOf(currentChunk) >= (Integer.valueOf(chunks) - 1);
236
237
238 if (file.exists()) {
239 try {
240 long size = Long.valueOf(request.getParameter(RESUMABLE_SIZE));
241 long uploadedSize = file.length();
242 if (!(isLastChunck && uploadedSize == size)) {
243
244 FileUtil.appendFile(file, appendedFile);
245 }
246 } catch (Exception e) {
247 response.setStatus(501);
248 return null;
249 }
250 } else {
251
252
253 File outFile = new File(file.getPath());
254 try {
255 FileUtil.writeFileToDisk(acceptedFiles.get(0), outFile);
256 } catch (Exception e) {
257 response.setStatus(501);
258 return null;
259 }
260 }
261
262
263 if (!isLastChunck) {
264 GboatAppContext.output(Boolean.TRUE);
265 return null;
266 } else {
267
268 List<File> resultList = new ArrayList<File>();
269 resultList.add(file);
270 filesToCleanup.add(file);
271 params.put(inputName, resultList.toArray(new File[acceptedFiles.size()]));
272 }
273
274 }
275 }
276
277 }
278 }
279 } else {
280 logger.warn(getTextMessage(action, "struts.messages.invalid.file", new String[] { inputName }));
281 }
282 } else {
283 logger.warn(getTextMessage(action, "struts.messages.invalid.content.type", new String[] { inputName }));
284 }
285 }
286
287
288 String rt = null;
289 try {
290 rt = invocation.invoke();
291 } finally {
292 cleanupResumableUpoadedFiles(filesToCleanup);
293 }
294 return rt;
295 }
296
297 private void cleanupResumableUpoadedFiles(List<File> files) {
298 if (null != files) {
299 for (File file : files) {
300 if (file.exists()) {
301 try {
302 file.delete();
303 } catch (Exception e) {
304 }
305 }
306 }
307 }
308 }
309
310 private String getBreak_Point_TempDir(ServletContext servletContext) {
311
312 getTempDir(servletContext);
313
314 return getMultipartSaveDir();
315
316 }
317
318 private String getFullMD5FileName(HttpServletRequest request) throws Exception {
319
320 String fileNameUpload = request.getParameter(RESUMABLE_FILENAME);
321 String modificationDate = request.getParameter(RESUMABLE_MODIFICATION_DATE);
322 String size = request.getParameter(RESUMABLE_SIZE);
323
324 String md5FileName = MD5Util.getMD5String(fileNameUpload + size + modificationDate);
325
326 String fullMD4FileName = md5FileName + fileNameUpload.substring(fileNameUpload.lastIndexOf("."));
327
328 return fullMD4FileName;
329 }
330
331 private boolean isNonEmpty(Object[] objArray) {
332 boolean result = false;
333 for (int index = 0; index < objArray.length && !result; index++) {
334 if (objArray[index] != null) {
335 result = true;
336 }
337 }
338 return result;
339 }
340
341
342
343
344
345
346
347 private String getTempDir(ServletContext servletContext) {
348 String saveDir = multipartSaveDir.trim();
349
350 if (saveDir.equals("")) {
351 File tempdir = (File) servletContext.getAttribute("javax.servlet.context.tempdir");
352 logger.info("Unable to find 'struts.multipart.saveDir' property setting. Defaulting to javax.servlet.context.tempdir");
353
354 if (!tempdir.exists()) {
355 if (tempdir.mkdir() == false) {
356 String logMessage;
357 try {
358 logMessage = "Could not find create multipart save directory '" + tempdir.getCanonicalPath() + "'.";
359 } catch (IOException e) {
360 logMessage = "Could not find create multipart save directory '" + tempdir.toString() + "'.";
361 }
362 logger.warn(logMessage);
363 }
364 }
365
366 if (tempdir != null) {
367 saveDir = tempdir.toString();
368 setMultipartSaveDir(tempdir.toString());
369 }
370 } else {
371 File gboat2TempFile = new File(multipartSaveDir);
372 if (!gboat2TempFile.exists()) {
373 if (gboat2TempFile.mkdir() == false) {
374 String logMessage;
375 try {
376 logMessage = "Could not find create multipart save directory '" + gboat2TempFile.getCanonicalPath() + "'.";
377 } catch (IOException e) {
378 logMessage = "Could not find create multipart save directory '" + gboat2TempFile.toString() + "'.";
379 }
380 logger.warn(logMessage);
381 }
382 }
383 }
384
385 if (logger.isDebugEnabled()) {
386 logger.debug("saveDir=" + saveDir);
387 }
388
389 return saveDir;
390 }
391 }