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