1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.servlets;
20
21 import java.io.BufferedInputStream;
22 import java.io.ByteArrayOutputStream;
23 import java.io.File;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.UnsupportedEncodingException;
27 import java.nio.charset.Charset;
28 import java.nio.charset.StandardCharsets;
29 import java.nio.charset.UnsupportedCharsetException;
30 import java.util.Collection;
31 import java.util.Collections;
32 import java.util.Enumeration;
33 import java.util.HashMap;
34 import java.util.Iterator;
35 import java.util.List;
36 import java.util.Map;
37
38 import javax.servlet.Filter;
39 import javax.servlet.FilterChain;
40 import javax.servlet.FilterConfig;
41 import javax.servlet.MultipartConfigElement;
42 import javax.servlet.ServletContext;
43 import javax.servlet.ServletException;
44 import javax.servlet.ServletRequest;
45 import javax.servlet.ServletResponse;
46 import javax.servlet.http.HttpServletRequest;
47 import javax.servlet.http.HttpServletRequestWrapper;
48 import javax.servlet.http.Part;
49
50 import org.eclipse.jetty.http.MimeTypes;
51 import org.eclipse.jetty.util.IO;
52 import org.eclipse.jetty.util.LazyList;
53 import org.eclipse.jetty.util.MultiMap;
54 import org.eclipse.jetty.util.MultiPartInputStreamParser;
55 import org.eclipse.jetty.util.log.Log;
56 import org.eclipse.jetty.util.log.Logger;
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97 @Deprecated
98 public class MultiPartFilter implements Filter
99 {
100 private static final Logger LOG = Log.getLogger(MultiPartFilter.class);
101 public final static String CONTENT_TYPE_SUFFIX=".org.eclipse.jetty.servlet.contentType";
102 private final static String MULTIPART = "org.eclipse.jetty.servlet.MultiPartFile.multiPartInputStream";
103 private File tempdir;
104 private boolean _deleteFiles;
105 private ServletContext _context;
106 private int _fileOutputBuffer = 0;
107 private boolean _writeFilesWithFilenames = false;
108 private long _maxFileSize = -1L;
109 private long _maxRequestSize = -1L;
110 private int _maxFormKeys = Integer.getInteger("org.eclipse.jetty.server.Request.maxFormKeys", 1000);
111
112
113
114
115
116 public void init(FilterConfig filterConfig) throws ServletException
117 {
118 tempdir=(File)filterConfig.getServletContext().getAttribute("javax.servlet.context.tempdir");
119 _deleteFiles="true".equals(filterConfig.getInitParameter("deleteFiles"));
120 String fileOutputBuffer = filterConfig.getInitParameter("fileOutputBuffer");
121 if(fileOutputBuffer!=null)
122 _fileOutputBuffer = Integer.parseInt(fileOutputBuffer);
123 String maxFileSize = filterConfig.getInitParameter("maxFileSize");
124 if (maxFileSize != null)
125 _maxFileSize = Long.parseLong(maxFileSize.trim());
126 String maxRequestSize = filterConfig.getInitParameter("maxRequestSize");
127 if (maxRequestSize != null)
128 _maxRequestSize = Long.parseLong(maxRequestSize.trim());
129
130 _context=filterConfig.getServletContext();
131 String mfks = filterConfig.getInitParameter("maxFormKeys");
132 if (mfks!=null)
133 _maxFormKeys=Integer.parseInt(mfks);
134 _writeFilesWithFilenames = "true".equalsIgnoreCase(filterConfig.getInitParameter("writeFilesWithFilenames"));
135 }
136
137
138
139
140
141
142 public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain)
143 throws IOException, ServletException
144 {
145 HttpServletRequest srequest=(HttpServletRequest)request;
146 if(srequest.getContentType()==null||!srequest.getContentType().startsWith("multipart/form-data"))
147 {
148 chain.doFilter(request,response);
149 return;
150 }
151
152 InputStream in = new BufferedInputStream(request.getInputStream());
153 String content_type=srequest.getContentType();
154
155
156 MultiMap params = new MultiMap();
157 for (Map.Entry<String, String[]> entry : request.getParameterMap().entrySet())
158 {
159 Object value = entry.getValue();
160 if (value instanceof String[])
161 params.addValues(entry.getKey(), (String[])value);
162 else
163 params.add(entry.getKey(), value);
164 }
165
166 MultipartConfigElement config = new MultipartConfigElement(tempdir.getCanonicalPath(), _maxFileSize, _maxRequestSize, _fileOutputBuffer);
167 MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(in, content_type, config, tempdir);
168 mpis.setDeleteOnExit(_deleteFiles);
169 mpis.setWriteFilesWithFilenames(_writeFilesWithFilenames);
170 request.setAttribute(MULTIPART, mpis);
171 try
172 {
173 Collection<Part> parts = mpis.getParts();
174 if (parts != null)
175 {
176 Iterator<Part> itor = parts.iterator();
177 while (itor.hasNext() && params.size() < _maxFormKeys)
178 {
179 Part p = itor.next();
180 if (LOG.isDebugEnabled())
181 LOG.debug("{}",p);
182 MultiPartInputStreamParser.MultiPart mp = (MultiPartInputStreamParser.MultiPart)p;
183 if (mp.getFile() != null)
184 {
185 request.setAttribute(mp.getName(),mp.getFile());
186 if (mp.getContentDispositionFilename() != null)
187 {
188 params.add(mp.getName(), mp.getContentDispositionFilename());
189 if (mp.getContentType() != null)
190 params.add(mp.getName()+CONTENT_TYPE_SUFFIX, mp.getContentType());
191 }
192 }
193 else
194 {
195 ByteArrayOutputStream bytes = new ByteArrayOutputStream();
196 IO.copy(p.getInputStream(), bytes);
197 params.add(p.getName(), bytes.toByteArray());
198 if (p.getContentType() != null)
199 params.add(p.getName()+CONTENT_TYPE_SUFFIX, p.getContentType());
200 }
201 }
202 }
203
204
205 chain.doFilter(new Wrapper(srequest,params),response);
206 }
207 finally
208 {
209 deleteFiles(request);
210 }
211 }
212
213
214
215 private void deleteFiles(ServletRequest request)
216 {
217 if (!_deleteFiles)
218 return;
219
220 MultiPartInputStreamParser mpis = (MultiPartInputStreamParser)request.getAttribute(MULTIPART);
221 if (mpis != null)
222 {
223 try
224 {
225 mpis.deleteParts();
226 }
227 catch (Exception e)
228 {
229 _context.log("Error deleting multipart tmp files", e);
230 }
231 }
232 request.removeAttribute(MULTIPART);
233 }
234
235
236
237
238
239 public void destroy()
240 {
241 }
242
243
244
245 private static class Wrapper extends HttpServletRequestWrapper
246 {
247 Charset _encoding=StandardCharsets.UTF_8;
248 MultiMap<Object> _params;
249
250
251 public Wrapper(HttpServletRequest request, MultiMap map)
252 {
253 super(request);
254 this._params=map;
255 }
256
257
258
259
260
261 @Override
262 public int getContentLength()
263 {
264 return 0;
265 }
266
267
268
269
270
271 @Override
272 public String getParameter(String name)
273 {
274 Object o=_params.get(name);
275 if (!(o instanceof byte[]) && LazyList.size(o)>0)
276 o=LazyList.get(o,0);
277
278 if (o instanceof byte[])
279 {
280 try
281 {
282 return getParameterBytesAsString(name, (byte[])o);
283 }
284 catch(Exception e)
285 {
286 LOG.warn(e);
287 }
288 }
289 else if (o!=null)
290 return String.valueOf(o);
291 return null;
292 }
293
294
295
296
297
298 @Override
299 public Map<String, String[]> getParameterMap()
300 {
301 Map<String, String[]> cmap = new HashMap<String,String[]>();
302
303 for ( Object key : _params.keySet() )
304 {
305 cmap.put((String)key,getParameterValues((String)key));
306 }
307
308 return Collections.unmodifiableMap(cmap);
309 }
310
311
312
313
314
315 @Override
316 public Enumeration<String> getParameterNames()
317 {
318 return Collections.enumeration(_params.keySet());
319 }
320
321
322
323
324
325 @Override
326 public String[] getParameterValues(String name)
327 {
328 List l=_params.getValues(name);
329 if (l==null || l.size()==0)
330 return new String[0];
331 String[] v = new String[l.size()];
332 for (int i=0;i<l.size();i++)
333 {
334 Object o=l.get(i);
335 if (o instanceof byte[])
336 {
337 try
338 {
339 v[i]=getParameterBytesAsString(name, (byte[])o);
340 }
341 catch(Exception e)
342 {
343 throw new RuntimeException(e);
344 }
345 }
346 else if (o instanceof String)
347 v[i]=(String)o;
348 }
349 return v;
350 }
351
352
353
354
355
356 @Override
357 public void setCharacterEncoding(String enc)
358 throws UnsupportedEncodingException
359 {
360 try
361 {
362 _encoding=Charset.forName(enc);
363 }
364 catch (UnsupportedCharsetException e)
365 {
366 throw new UnsupportedEncodingException(e.getMessage());
367 }
368 }
369
370
371
372 private String getParameterBytesAsString (String name, byte[] bytes)
373 throws UnsupportedEncodingException
374 {
375
376 Object ct = _params.getValue(name+CONTENT_TYPE_SUFFIX,0);
377
378 Charset contentType = _encoding;
379 if (ct != null)
380 {
381 String tmp = MimeTypes.getCharsetFromContentType((String)ct);
382 try
383 {
384 contentType = (tmp == null?_encoding:Charset.forName(tmp));
385 }
386 catch (UnsupportedCharsetException e)
387 {
388 throw new UnsupportedEncodingException(e.getMessage());
389 }
390 }
391
392 return new String(bytes,contentType);
393 }
394 }
395 }