1
2
3
4
5
6
7
8
9
10
11
12
13 package org.eclipse.jetty.servlets;
14
15 import java.io.BufferedInputStream;
16 import java.io.BufferedOutputStream;
17 import java.io.ByteArrayOutputStream;
18 import java.io.File;
19 import java.io.FileOutputStream;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.OutputStream;
23 import java.io.UnsupportedEncodingException;
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.Enumeration;
28 import java.util.HashMap;
29 import java.util.Iterator;
30 import java.util.List;
31 import java.util.Map;
32
33 import javax.servlet.Filter;
34 import javax.servlet.FilterChain;
35 import javax.servlet.FilterConfig;
36 import javax.servlet.MultipartConfigElement;
37 import javax.servlet.ServletContext;
38 import javax.servlet.ServletException;
39 import javax.servlet.ServletRequest;
40 import javax.servlet.ServletResponse;
41 import javax.servlet.http.HttpServletRequest;
42 import javax.servlet.http.HttpServletRequestWrapper;
43 import javax.servlet.http.Part;
44
45
46 import org.eclipse.jetty.util.IO;
47 import org.eclipse.jetty.util.LazyList;
48 import org.eclipse.jetty.util.MultiMap;
49 import org.eclipse.jetty.util.MultiPartInputStream;
50 import org.eclipse.jetty.util.QuotedStringTokenizer;
51 import org.eclipse.jetty.util.StringUtil;
52 import org.eclipse.jetty.util.TypeUtil;
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78 public class MultiPartFilter implements Filter
79 {
80 public final static String CONTENT_TYPE_SUFFIX=".org.eclipse.jetty.servlet.contentType";
81 private final static String FILES ="org.eclipse.jetty.servlet.MultiPartFilter.files";
82 private File tempdir;
83 private boolean _deleteFiles;
84 private ServletContext _context;
85 private int _fileOutputBuffer = 0;
86 private long _maxFileSize = -1L;
87 private long _maxRequestSize = -1L;
88 private int _maxFormKeys = Integer.getInteger("org.eclipse.jetty.server.Request.maxFormKeys",1000).intValue();
89
90
91
92
93
94 public void init(FilterConfig filterConfig) throws ServletException
95 {
96 tempdir=(File)filterConfig.getServletContext().getAttribute("javax.servlet.context.tempdir");
97 _deleteFiles="true".equals(filterConfig.getInitParameter("deleteFiles"));
98 String fileOutputBuffer = filterConfig.getInitParameter("fileOutputBuffer");
99 if(fileOutputBuffer!=null)
100 _fileOutputBuffer = Integer.parseInt(fileOutputBuffer);
101 String maxFileSize = filterConfig.getInitParameter("maxFileSize");
102 if (maxFileSize != null)
103 _maxFileSize = Long.parseLong(maxFileSize.trim());
104 String maxRequestSize = filterConfig.getInitParameter("maxRequestSize");
105 if (maxRequestSize != null)
106 _maxRequestSize = Long.parseLong(maxRequestSize.trim());
107
108 _context=filterConfig.getServletContext();
109 String mfks = filterConfig.getInitParameter("maxFormKeys");
110 if (mfks!=null)
111 _maxFormKeys=Integer.parseInt(mfks);
112 }
113
114
115
116
117
118
119 public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain)
120 throws IOException, ServletException
121 {
122 HttpServletRequest srequest=(HttpServletRequest)request;
123 if(srequest.getContentType()==null||!srequest.getContentType().startsWith("multipart/form-data"))
124 {
125 chain.doFilter(request,response);
126 return;
127 }
128
129 InputStream in = new BufferedInputStream(request.getInputStream());
130 String content_type=srequest.getContentType();
131
132
133 MultiMap<String> params = new MultiMap<String>();
134 for (Iterator<Map.Entry<String,String[]>> i = request.getParameterMap().entrySet().iterator();i.hasNext();)
135 {
136 Map.Entry<String,String[]> entry=i.next();
137 Object value=entry.getValue();
138 if (value instanceof String[])
139 params.addValues(entry.getKey(),(String[])value);
140 else
141 params.add(entry.getKey(),value);
142 }
143
144 MultipartConfigElement config = new MultipartConfigElement(tempdir.getCanonicalPath(), _maxFileSize, _maxRequestSize, _fileOutputBuffer);
145 MultiPartInputStream mpis = new MultiPartInputStream(in, content_type, config, tempdir);
146
147
148 try
149 {
150 Collection<Part> parts = mpis.getParts();
151 if (parts != null)
152 {
153 Iterator<Part> itor = parts.iterator();
154 while (itor.hasNext() && params.size() < _maxFormKeys)
155 {
156 Part p = itor.next();
157 MultiPartInputStream.MultiPart mp = (MultiPartInputStream.MultiPart)p;
158 if (mp.getFile() != null)
159 {
160 request.setAttribute(mp.getName(),mp.getFile());
161 if (mp.getContentDispositionFilename() != null)
162 {
163 params.add(mp.getName(), mp.getContentDispositionFilename());
164 if (mp.getContentType() != null)
165 params.add(mp.getName()+CONTENT_TYPE_SUFFIX, mp.getContentType());
166 }
167 if (_deleteFiles)
168 {
169 mp.getFile().deleteOnExit();
170
171 ArrayList files = (ArrayList)request.getAttribute(FILES);
172 if (files==null)
173 {
174 files=new ArrayList();
175 request.setAttribute(FILES,files);
176 }
177 files.add(mp.getFile());
178 }
179 }
180 else
181 {
182 ByteArrayOutputStream bytes = new ByteArrayOutputStream();
183 IO.copy(p.getInputStream(), bytes);
184 params.add(p.getName(), bytes.toByteArray());
185 if (p.getContentType() != null)
186 params.add(p.getName()+CONTENT_TYPE_SUFFIX, p.getContentType());
187 }
188 }
189 }
190
191
192 chain.doFilter(new Wrapper(srequest,params),response);
193 }
194 finally
195 {
196 deleteFiles(request);
197 }
198 }
199
200 private void deleteFiles(ServletRequest request)
201 {
202 ArrayList files = (ArrayList)request.getAttribute(FILES);
203 if (files!=null)
204 {
205 Iterator iter = files.iterator();
206 while (iter.hasNext())
207 {
208 File file=(File)iter.next();
209 try
210 {
211 file.delete();
212 }
213 catch(Exception e)
214 {
215 _context.log("failed to delete "+file,e);
216 }
217 }
218 }
219 }
220
221
222 private String value(String nameEqualsValue)
223 {
224 return nameEqualsValue.substring(nameEqualsValue.indexOf('=')+1).trim();
225 }
226
227
228
229
230
231 public void destroy()
232 {
233 }
234
235
236
237 private static class Wrapper extends HttpServletRequestWrapper
238 {
239 String _encoding=StringUtil.__UTF8;
240 MultiMap _params;
241
242
243
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 String s=new String((byte[])o,_encoding);
278 return s;
279 }
280 catch(Exception e)
281 {
282 e.printStackTrace();
283 }
284 }
285 else if (o!=null)
286 return String.valueOf(o);
287 return null;
288 }
289
290
291
292
293
294 @Override
295 public Map getParameterMap()
296 {
297 Map<String, String> cmap = new HashMap<String,String>();
298
299 for ( Object key : _params.keySet() )
300 {
301 cmap.put((String)key,getParameter((String)key));
302 }
303
304 return Collections.unmodifiableMap(cmap);
305 }
306
307
308
309
310
311 @Override
312 public Enumeration getParameterNames()
313 {
314 return Collections.enumeration(_params.keySet());
315 }
316
317
318
319
320
321 @Override
322 public String[] getParameterValues(String name)
323 {
324 List l=_params.getValues(name);
325 if (l==null || l.size()==0)
326 return new String[0];
327 String[] v = new String[l.size()];
328 for (int i=0;i<l.size();i++)
329 {
330 Object o=l.get(i);
331 if (o instanceof byte[])
332 {
333 try
334 {
335 v[i]=new String((byte[])o,_encoding);
336 }
337 catch(Exception e)
338 {
339 throw new RuntimeException(e);
340 }
341 }
342 else if (o instanceof String)
343 v[i]=(String)o;
344 }
345 return v;
346 }
347
348
349
350
351
352 @Override
353 public void setCharacterEncoding(String enc)
354 throws UnsupportedEncodingException
355 {
356 _encoding=enc;
357 }
358 }
359 }