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 long _maxFileSize = -1L;
108 private long _maxRequestSize = -1L;
109 private int _maxFormKeys = Integer.getInteger("org.eclipse.jetty.server.Request.maxFormKeys", 1000);
110
111
112
113
114
115 public void init(FilterConfig filterConfig) throws ServletException
116 {
117 tempdir=(File)filterConfig.getServletContext().getAttribute("javax.servlet.context.tempdir");
118 _deleteFiles="true".equals(filterConfig.getInitParameter("deleteFiles"));
119 String fileOutputBuffer = filterConfig.getInitParameter("fileOutputBuffer");
120 if(fileOutputBuffer!=null)
121 _fileOutputBuffer = Integer.parseInt(fileOutputBuffer);
122 String maxFileSize = filterConfig.getInitParameter("maxFileSize");
123 if (maxFileSize != null)
124 _maxFileSize = Long.parseLong(maxFileSize.trim());
125 String maxRequestSize = filterConfig.getInitParameter("maxRequestSize");
126 if (maxRequestSize != null)
127 _maxRequestSize = Long.parseLong(maxRequestSize.trim());
128
129 _context=filterConfig.getServletContext();
130 String mfks = filterConfig.getInitParameter("maxFormKeys");
131 if (mfks!=null)
132 _maxFormKeys=Integer.parseInt(mfks);
133 }
134
135
136
137
138
139
140 public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain)
141 throws IOException, ServletException
142 {
143 HttpServletRequest srequest=(HttpServletRequest)request;
144 if(srequest.getContentType()==null||!srequest.getContentType().startsWith("multipart/form-data"))
145 {
146 chain.doFilter(request,response);
147 return;
148 }
149
150 InputStream in = new BufferedInputStream(request.getInputStream());
151 String content_type=srequest.getContentType();
152
153
154 MultiMap params = new MultiMap();
155 for (Map.Entry<String, String[]> entry : request.getParameterMap().entrySet())
156 {
157 Object value = entry.getValue();
158 if (value instanceof String[])
159 params.addValues(entry.getKey(), (String[])value);
160 else
161 params.add(entry.getKey(), value);
162 }
163
164 MultipartConfigElement config = new MultipartConfigElement(tempdir.getCanonicalPath(), _maxFileSize, _maxRequestSize, _fileOutputBuffer);
165 MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(in, content_type, config, tempdir);
166 mpis.setDeleteOnExit(_deleteFiles);
167 request.setAttribute(MULTIPART, mpis);
168 try
169 {
170 Collection<Part> parts = mpis.getParts();
171 if (parts != null)
172 {
173 Iterator<Part> itor = parts.iterator();
174 while (itor.hasNext() && params.size() < _maxFormKeys)
175 {
176 Part p = itor.next();
177 MultiPartInputStreamParser.MultiPart mp = (MultiPartInputStreamParser.MultiPart)p;
178 if (mp.getFile() != null)
179 {
180 request.setAttribute(mp.getName(),mp.getFile());
181 if (mp.getContentDispositionFilename() != null)
182 {
183 params.add(mp.getName(), mp.getContentDispositionFilename());
184 if (mp.getContentType() != null)
185 params.add(mp.getName()+CONTENT_TYPE_SUFFIX, mp.getContentType());
186 }
187 }
188 else
189 {
190 ByteArrayOutputStream bytes = new ByteArrayOutputStream();
191 IO.copy(p.getInputStream(), bytes);
192 params.add(p.getName(), bytes.toByteArray());
193 if (p.getContentType() != null)
194 params.add(p.getName()+CONTENT_TYPE_SUFFIX, p.getContentType());
195 }
196 }
197 }
198
199
200 chain.doFilter(new Wrapper(srequest,params),response);
201 }
202 finally
203 {
204 deleteFiles(request);
205 }
206 }
207
208
209
210 private void deleteFiles(ServletRequest request)
211 {
212 if (!_deleteFiles)
213 return;
214
215 MultiPartInputStreamParser mpis = (MultiPartInputStreamParser)request.getAttribute(MULTIPART);
216 if (mpis != null)
217 {
218 try
219 {
220 mpis.deleteParts();
221 }
222 catch (Exception e)
223 {
224 _context.log("Error deleting multipart tmp files", e);
225 }
226 }
227 request.removeAttribute(MULTIPART);
228 }
229
230
231
232
233
234 public void destroy()
235 {
236 }
237
238
239
240 private static class Wrapper extends HttpServletRequestWrapper
241 {
242 Charset _encoding=StandardCharsets.UTF_8;
243 MultiMap<Object> _params;
244
245
246 public Wrapper(HttpServletRequest request, MultiMap map)
247 {
248 super(request);
249 this._params=map;
250 }
251
252
253
254
255
256 @Override
257 public int getContentLength()
258 {
259 return 0;
260 }
261
262
263
264
265
266 @Override
267 public String getParameter(String name)
268 {
269 Object o=_params.get(name);
270 if (!(o instanceof byte[]) && LazyList.size(o)>0)
271 o=LazyList.get(o,0);
272
273 if (o instanceof byte[])
274 {
275 try
276 {
277 return getParameterBytesAsString(name, (byte[])o);
278 }
279 catch(Exception e)
280 {
281 LOG.warn(e);
282 }
283 }
284 else if (o!=null)
285 return String.valueOf(o);
286 return null;
287 }
288
289
290
291
292
293 @Override
294 public Map<String, String[]> getParameterMap()
295 {
296 Map<String, String[]> cmap = new HashMap<String,String[]>();
297
298 for ( Object key : _params.keySet() )
299 {
300 cmap.put((String)key,getParameterValues((String)key));
301 }
302
303 return Collections.unmodifiableMap(cmap);
304 }
305
306
307
308
309
310 @Override
311 public Enumeration<String> getParameterNames()
312 {
313 return Collections.enumeration(_params.keySet());
314 }
315
316
317
318
319
320 @Override
321 public String[] getParameterValues(String name)
322 {
323 List l=_params.getValues(name);
324 if (l==null || l.size()==0)
325 return new String[0];
326 String[] v = new String[l.size()];
327 for (int i=0;i<l.size();i++)
328 {
329 Object o=l.get(i);
330 if (o instanceof byte[])
331 {
332 try
333 {
334 v[i]=getParameterBytesAsString(name, (byte[])o);
335 }
336 catch(Exception e)
337 {
338 throw new RuntimeException(e);
339 }
340 }
341 else if (o instanceof String)
342 v[i]=(String)o;
343 }
344 return v;
345 }
346
347
348
349
350
351 @Override
352 public void setCharacterEncoding(String enc)
353 throws UnsupportedEncodingException
354 {
355 try
356 {
357 _encoding=Charset.forName(enc);
358 }
359 catch (UnsupportedCharsetException e)
360 {
361 throw new UnsupportedEncodingException(e.getMessage());
362 }
363 }
364
365
366
367 private String getParameterBytesAsString (String name, byte[] bytes)
368 throws UnsupportedEncodingException
369 {
370
371 Object ct = _params.getValue(name+CONTENT_TYPE_SUFFIX,0);
372
373 Charset contentType = _encoding;
374 if (ct != null)
375 {
376 String tmp = MimeTypes.getCharsetFromContentType((String)ct);
377 try
378 {
379 contentType = (tmp == null?_encoding:Charset.forName(tmp));
380 }
381 catch (UnsupportedCharsetException e)
382 {
383 throw new UnsupportedEncodingException(e.getMessage());
384 }
385 }
386
387 return new String(bytes,contentType);
388 }
389 }
390 }