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