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
178
179
180
181
182
183 if(name==null)
184 {
185 continue;
186 }
187
188 OutputStream out=null;
189 File file=null;
190 try
191 {
192 if (filename!=null && filename.length()>0)
193 {
194 file = File.createTempFile("MultiPart", "", tempdir);
195 out = new FileOutputStream(file);
196 if(_fileOutputBuffer>0)
197 out = new BufferedOutputStream(out, _fileOutputBuffer);
198 request.setAttribute(name,file);
199 params.put(name, filename);
200
201 if (_deleteFiles)
202 {
203 file.deleteOnExit();
204 ArrayList files = (ArrayList)request.getAttribute(FILES);
205 if (files==null)
206 {
207 files=new ArrayList();
208 request.setAttribute(FILES,files);
209 }
210 files.add(file);
211 }
212
213 }
214 else
215 out=new ByteArrayOutputStream();
216
217 int state=-2;
218 int c;
219 boolean cr=false;
220 boolean lf=false;
221
222
223 while(true)
224 {
225 int b=0;
226 while((c=(state!=-2)?state:in.read())!=-1)
227 {
228 state=-2;
229
230 if(c==13||c==10)
231 {
232 if(c==13)
233 state=in.read();
234 break;
235 }
236
237 if(b>=0&&b<byteBoundary.length&&c==byteBoundary[b])
238 b++;
239 else
240 {
241
242 if(cr)
243 out.write(13);
244 if(lf)
245 out.write(10);
246 cr=lf=false;
247 if(b>0)
248 out.write(byteBoundary,0,b);
249 b=-1;
250 out.write(c);
251 }
252 }
253
254 if((b>0&&b<byteBoundary.length-2)||(b==byteBoundary.length-1))
255 {
256 if(cr)
257 out.write(13);
258 if(lf)
259 out.write(10);
260 cr=lf=false;
261 out.write(byteBoundary,0,b);
262 b=-1;
263 }
264
265 if(b>0||c==-1)
266 {
267 if(b==byteBoundary.length)
268 lastPart=true;
269 if(state==10)
270 state=-2;
271 break;
272 }
273
274 if(cr)
275 out.write(13);
276 if(lf)
277 out.write(10);
278 cr=(c==13);
279 lf=(c==10||state==10);
280 if(state==10)
281 state=-2;
282 }
283 }
284 finally
285 {
286 out.close();
287 }
288
289 if (file==null)
290 {
291 bytes = ((ByteArrayOutputStream)out).toByteArray();
292 params.add(name,bytes);
293 }
294 }
295
296
297 chain.doFilter(new Wrapper(srequest,params),response);
298 }
299 finally
300 {
301 deleteFiles(request);
302 }
303 }
304
305 private void deleteFiles(ServletRequest request)
306 {
307 ArrayList files = (ArrayList)request.getAttribute(FILES);
308 if (files!=null)
309 {
310 Iterator iter = files.iterator();
311 while (iter.hasNext())
312 {
313 File file=(File)iter.next();
314 try
315 {
316 file.delete();
317 }
318 catch(Exception e)
319 {
320 _context.log("failed to delete "+file,e);
321 }
322 }
323 }
324 }
325
326 private String value(String nameEqualsValue)
327 {
328 String value=nameEqualsValue.substring(nameEqualsValue.indexOf('=')+1).trim();
329 int i=value.indexOf(';');
330 if(i>0)
331 value=value.substring(0,i);
332 if(value.startsWith("\""))
333 {
334 value=value.substring(1,value.indexOf('"',1));
335 }
336 else
337 {
338 i=value.indexOf(' ');
339 if(i>0)
340 value=value.substring(0,i);
341 }
342 return value;
343 }
344
345
346
347
348
349 public void destroy()
350 {
351 }
352
353 private static class Wrapper extends HttpServletRequestWrapper
354 {
355 String encoding="UTF-8";
356 MultiMap map;
357
358
359
360
361
362 public Wrapper(HttpServletRequest request, MultiMap map)
363 {
364 super(request);
365 this.map=map;
366 }
367
368
369
370
371
372 public int getContentLength()
373 {
374 return 0;
375 }
376
377
378
379
380
381 public String getParameter(String name)
382 {
383 Object o=map.get(name);
384 if (o instanceof byte[])
385 {
386 try
387 {
388 String s=new String((byte[])o,encoding);
389 return s;
390 }
391 catch(Exception e)
392 {
393 e.printStackTrace();
394 }
395 }
396 else if (o instanceof String)
397 return (String)o;
398 else if (o instanceof String[])
399 {
400 String[] s = (String[])o;
401 return s.length>0 ? s[0] : null;
402 }
403 return null;
404 }
405
406
407
408
409
410 public Map getParameterMap()
411 {
412 return map;
413 }
414
415
416
417
418
419 public Enumeration getParameterNames()
420 {
421 return Collections.enumeration(map.keySet());
422 }
423
424
425
426
427
428 public String[] getParameterValues(String name)
429 {
430 List l=map.getValues(name);
431 if (l==null || l.size()==0)
432 return new String[0];
433 String[] v = new String[l.size()];
434 for (int i=0;i<l.size();i++)
435 {
436 Object o=l.get(i);
437 if (o instanceof byte[])
438 {
439 try
440 {
441 v[i]=new String((byte[])o,encoding);
442 }
443 catch(Exception e)
444 {
445 e.printStackTrace();
446 }
447 }
448 else if (o instanceof String)
449 v[i]=(String)o;
450 }
451 return v;
452 }
453
454
455
456
457
458 public void setCharacterEncoding(String enc)
459 throws UnsupportedEncodingException
460 {
461 encoding=enc;
462 }
463 }
464 }