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