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