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