1
2
3
4
5
6
7
8
9
10
11
12
13
14 package org.mortbay.servlet;
15
16 import java.io.BufferedInputStream;
17 import java.io.BufferedOutputStream;
18 import java.io.ByteArrayOutputStream;
19 import java.io.File;
20 import java.io.FileNotFoundException;
21 import java.io.FileOutputStream;
22 import java.io.IOException;
23 import java.io.OutputStream;
24 import java.io.UnsupportedEncodingException;
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.Enumeration;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.StringTokenizer;
32
33 import javax.servlet.Filter;
34 import javax.servlet.FilterChain;
35 import javax.servlet.FilterConfig;
36 import javax.servlet.ServletContext;
37 import javax.servlet.ServletException;
38 import javax.servlet.ServletRequest;
39 import javax.servlet.ServletResponse;
40 import javax.servlet.http.HttpServletRequest;
41 import javax.servlet.http.HttpServletRequestWrapper;
42
43 import org.mortbay.util.MultiMap;
44 import org.mortbay.util.StringUtil;
45 import org.mortbay.util.TypeUtil;
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62 public class MultiPartFilter implements Filter
63 {
64 private final static String FILES ="org.mortbay.servlet.MultiPartFilter.files";
65 private File tempdir;
66 private boolean _deleteFiles;
67 private ServletContext _context;
68 private int _fileOutputBuffer = 0;
69
70
71
72
73
74 public void init(FilterConfig filterConfig) throws ServletException
75 {
76 tempdir=(File)filterConfig.getServletContext().getAttribute("javax.servlet.context.tempdir");
77 _deleteFiles="true".equals(filterConfig.getInitParameter("deleteFiles"));
78 String fileOutputBuffer = filterConfig.getInitParameter("fileOutputBuffer");
79 if(fileOutputBuffer!=null)
80 _fileOutputBuffer = Integer.parseInt(fileOutputBuffer);
81 _context=filterConfig.getServletContext();
82 }
83
84
85
86
87
88
89 public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain)
90 throws IOException, ServletException
91 {
92 HttpServletRequest srequest=(HttpServletRequest)request;
93 if(srequest.getContentType()==null||!srequest.getContentType().startsWith("multipart/form-data"))
94 {
95 chain.doFilter(request,response);
96 return;
97 }
98
99 BufferedInputStream in = new BufferedInputStream(request.getInputStream());
100 String content_type=srequest.getContentType();
101
102
103
104 String boundary="--"+value(content_type.substring(content_type.indexOf("boundary=")));
105 byte[] byteBoundary=(boundary+"--").getBytes(StringUtil.__ISO_8859_1);
106
107 MultiMap params = new MultiMap(request.getParameterMap());
108
109
110
111
112
113
114
115
116
117 try
118 {
119
120 byte[] bytes=TypeUtil.readLine(in);
121 String line=bytes==null?null:new String(bytes,"UTF-8");
122 if(line==null || !line.equals(boundary))
123 {
124 throw new IOException("Missing initial multi part boundary");
125 }
126
127
128 boolean lastPart=false;
129 String content_disposition=null;
130 while(!lastPart)
131 {
132 while(true)
133 {
134 bytes=TypeUtil.readLine(in);
135
136 if(bytes==null || bytes.length==0)
137 break;
138 line=new String(bytes,"UTF-8");
139
140
141 int c=line.indexOf(':',0);
142 if(c>0)
143 {
144 String key=line.substring(0,c).trim().toLowerCase();
145 String value=line.substring(c+1,line.length()).trim();
146 if(key.equals("content-disposition"))
147 content_disposition=value;
148 }
149 }
150
151 boolean form_data=false;
152 if(content_disposition==null)
153 {
154 throw new IOException("Missing content-disposition");
155 }
156
157 StringTokenizer tok=new StringTokenizer(content_disposition,";");
158 String name=null;
159 String filename=null;
160 while(tok.hasMoreTokens())
161 {
162 String t=tok.nextToken().trim();
163 String tl=t.toLowerCase();
164 if(t.startsWith("form-data"))
165 form_data=true;
166 else if(tl.startsWith("name="))
167 name=value(t);
168 else if(tl.startsWith("filename="))
169 filename=value(t);
170 }
171
172
173 if(!form_data)
174 {
175 continue;
176 }
177 if(name==null||name.length()==0)
178 {
179 continue;
180 }
181
182 OutputStream out=null;
183 File file=null;
184 try
185 {
186 if (filename!=null && filename.length()>0)
187 {
188 file = File.createTempFile("MultiPart", "", tempdir);
189 out = new FileOutputStream(file);
190 if(_fileOutputBuffer>0)
191 out = new BufferedOutputStream(out, _fileOutputBuffer);
192 request.setAttribute(name,file);
193 params.put(name, filename);
194
195 if (_deleteFiles)
196 {
197 file.deleteOnExit();
198 ArrayList files = (ArrayList)request.getAttribute(FILES);
199 if (files==null)
200 {
201 files=new ArrayList();
202 request.setAttribute(FILES,files);
203 }
204 files.add(file);
205 }
206
207 }
208 else
209 out=new ByteArrayOutputStream();
210
211 int state=-2;
212 int c;
213 boolean cr=false;
214 boolean lf=false;
215
216
217 while(true)
218 {
219 int b=0;
220 while((c=(state!=-2)?state:in.read())!=-1)
221 {
222 state=-2;
223
224 if(c==13||c==10)
225 {
226 if(c==13)
227 state=in.read();
228 break;
229 }
230
231 if(b>=0&&b<byteBoundary.length&&c==byteBoundary[b])
232 b++;
233 else
234 {
235
236 if(cr)
237 out.write(13);
238 if(lf)
239 out.write(10);
240 cr=lf=false;
241 if(b>0)
242 out.write(byteBoundary,0,b);
243 b=-1;
244 out.write(c);
245 }
246 }
247
248 if((b>0&&b<byteBoundary.length-2)||(b==byteBoundary.length-1))
249 {
250 if(cr)
251 out.write(13);
252 if(lf)
253 out.write(10);
254 cr=lf=false;
255 out.write(byteBoundary,0,b);
256 b=-1;
257 }
258
259 if(b>0||c==-1)
260 {
261 if(b==byteBoundary.length)
262 lastPart=true;
263 if(state==10)
264 state=-2;
265 break;
266 }
267
268 if(cr)
269 out.write(13);
270 if(lf)
271 out.write(10);
272 cr=(c==13);
273 lf=(c==10||state==10);
274 if(state==10)
275 state=-2;
276 }
277 }
278 finally
279 {
280 out.close();
281 }
282
283 if (file==null)
284 {
285 bytes = ((ByteArrayOutputStream)out).toByteArray();
286 params.add(name,bytes);
287 }
288 }
289
290
291 chain.doFilter(new Wrapper(srequest,params),response);
292 }
293 finally
294 {
295 deleteFiles(request);
296 }
297 }
298
299 private void deleteFiles(ServletRequest request)
300 {
301 ArrayList files = (ArrayList)request.getAttribute(FILES);
302 if (files!=null)
303 {
304 Iterator iter = files.iterator();
305 while (iter.hasNext())
306 {
307 File file=(File)iter.next();
308 try
309 {
310 file.delete();
311 }
312 catch(Exception e)
313 {
314 _context.log("failed to delete "+file,e);
315 }
316 }
317 }
318 }
319
320 private String value(String nameEqualsValue)
321 {
322 String value=nameEqualsValue.substring(nameEqualsValue.indexOf('=')+1).trim();
323 int i=value.indexOf(';');
324 if(i>0)
325 value=value.substring(0,i);
326 if(value.startsWith("\""))
327 {
328 value=value.substring(1,value.indexOf('"',1));
329 }
330 else
331 {
332 i=value.indexOf(' ');
333 if(i>0)
334 value=value.substring(0,i);
335 }
336 return value;
337 }
338
339
340
341
342
343 public void destroy()
344 {
345 }
346
347 private static class Wrapper extends HttpServletRequestWrapper
348 {
349 String encoding="UTF-8";
350 MultiMap map;
351
352
353
354
355
356 public Wrapper(HttpServletRequest request, MultiMap map)
357 {
358 super(request);
359 this.map=map;
360 }
361
362
363
364
365
366 public int getContentLength()
367 {
368 return 0;
369 }
370
371
372
373
374
375 public String getParameter(String name)
376 {
377 Object o=map.get(name);
378 if (o instanceof byte[])
379 {
380 try
381 {
382 String s=new String((byte[])o,encoding);
383 return s;
384 }
385 catch(Exception e)
386 {
387 e.printStackTrace();
388 }
389 }
390 else if (o instanceof String)
391 return (String)o;
392 else if (o instanceof String[])
393 {
394 String[] s = (String[])o;
395 return s.length>0 ? s[0] : null;
396 }
397 return null;
398 }
399
400
401
402
403
404 public Map getParameterMap()
405 {
406 return map;
407 }
408
409
410
411
412
413 public Enumeration getParameterNames()
414 {
415 return Collections.enumeration(map.keySet());
416 }
417
418
419
420
421
422 public String[] getParameterValues(String name)
423 {
424 List l=map.getValues(name);
425 if (l==null || l.size()==0)
426 return new String[0];
427 String[] v = new String[l.size()];
428 for (int i=0;i<l.size();i++)
429 {
430 Object o=l.get(i);
431 if (o instanceof byte[])
432 {
433 try
434 {
435 v[i]=new String((byte[])o,encoding);
436 }
437 catch(Exception e)
438 {
439 e.printStackTrace();
440 }
441 }
442 else if (o instanceof String)
443 v[i]=(String)o;
444 }
445 return v;
446 }
447
448
449
450
451
452 public void setCharacterEncoding(String enc)
453 throws UnsupportedEncodingException
454 {
455 encoding=enc;
456 }
457 }
458 }