KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mortbay > servlet > MultiPartFilter


1 // ========================================================================
2
// $Id: MultiPartFilter.java,v 1.7 2005/11/03 18:21:59 gregwilkins Exp $
3
// Copyright 1996-2004 Mort Bay Consulting Pty. Ltd.
4
// ------------------------------------------------------------------------
5
// Licensed under the Apache License, Version 2.0 (the "License");
6
// you may not use this file except in compliance with the License.
7
// You may obtain a copy of the License at
8
// http://www.apache.org/licenses/LICENSE-2.0
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
// ========================================================================
15
package org.mortbay.servlet;
16
17 import java.io.ByteArrayOutputStream JavaDoc;
18 import java.io.File JavaDoc;
19 import java.io.FileOutputStream JavaDoc;
20 import java.io.IOException JavaDoc;
21 import java.io.OutputStream JavaDoc;
22 import java.io.UnsupportedEncodingException JavaDoc;
23 import java.util.Collections JavaDoc;
24 import java.util.Enumeration JavaDoc;
25 import java.util.List JavaDoc;
26 import java.util.Map JavaDoc;
27 import java.util.StringTokenizer JavaDoc;
28
29 import javax.servlet.Filter JavaDoc;
30 import javax.servlet.FilterChain JavaDoc;
31 import javax.servlet.FilterConfig JavaDoc;
32 import javax.servlet.ServletException JavaDoc;
33 import javax.servlet.ServletRequest JavaDoc;
34 import javax.servlet.ServletResponse JavaDoc;
35 import javax.servlet.http.HttpServletRequest JavaDoc;
36 import javax.servlet.http.HttpServletRequestWrapper JavaDoc;
37
38 import org.apache.commons.logging.Log;
39 import org.mortbay.log.LogFactory;
40 import org.mortbay.util.IO;
41 import org.mortbay.util.LineInput;
42 import org.mortbay.util.MultiMap;
43 import org.mortbay.util.StringUtil;
44
45 /* ------------------------------------------------------------ */
46 /**
47  * Multipart Form Data Filter.
48  * <p>
49  * This class decodes the multipart/form-data stream sent by a HTML form that uses a file input
50  * item. Any files sent are stored to a tempary file and a File object added to the request
51  * as an attribute. All other values are made available via the normal getParameter API and
52  * the setCharacterEncoding mechanism is respected when converting bytes to Strings.
53  *
54  * @version $Id: MultiPartFilter.java,v 1.7 2005/11/03 18:21:59 gregwilkins Exp $
55  * @author Greg Wilkins
56  * @author Jim Crossley
57  */

58 public class MultiPartFilter implements Filter JavaDoc
59 {
60     private static Log log=LogFactory.getLog(MultiPartFilter.class);
61     private File JavaDoc tempdir;
62
63     /* ------------------------------------------------------------------------------- */
64     /**
65      * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
66      */

67     public void init(FilterConfig JavaDoc filterConfig) throws ServletException JavaDoc
68     {
69         tempdir=(File JavaDoc)filterConfig.getServletContext().getAttribute("javax.servlet.context.tempdir");
70     }
71
72     /* ------------------------------------------------------------------------------- */
73     /**
74      * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest,
75      * javax.servlet.ServletResponse, javax.servlet.FilterChain)
76      */

77     public void doFilter(ServletRequest JavaDoc request,ServletResponse JavaDoc response,FilterChain JavaDoc chain) throws IOException JavaDoc,
78             ServletException JavaDoc
79     {
80         HttpServletRequest JavaDoc srequest=(HttpServletRequest JavaDoc)request;
81         if(srequest.getContentType()==null||!srequest.getContentType().startsWith("multipart/form-data"))
82         {
83             chain.doFilter(request,response);
84             return;
85         }
86         LineInput in=new LineInput(request.getInputStream());
87         String JavaDoc content_type=srequest.getContentType();
88         String JavaDoc boundary="--"+value(content_type.substring(content_type.indexOf("boundary=")));
89         byte[] byteBoundary=(boundary+"--").getBytes(StringUtil.__ISO_8859_1);
90         MultiMap params = new MultiMap();
91         
92         // Get first boundary
93
String JavaDoc line=in.readLine();
94         if(!line.equals(boundary))
95         {
96             log.warn(line);
97             throw new IOException JavaDoc("Missing initial multi part boundary");
98         }
99         
100         // Read each part
101
boolean lastPart=false;
102         String JavaDoc content_disposition=null;
103         while(!lastPart)
104         {
105             while((line=in.readLine())!=null)
106             {
107                 // If blank line, end of part headers
108
if(line.length()==0)
109                     break;
110                 // place part header key and value in map
111
int c=line.indexOf(':',0);
112                 if(c>0)
113                 {
114                     String JavaDoc key=line.substring(0,c).trim().toLowerCase();
115                     String JavaDoc value=line.substring(c+1,line.length()).trim();
116                     if(key.equals("content-disposition"))
117                         content_disposition=value;
118                 }
119             }
120             // Extract content-disposition
121
boolean form_data=false;
122             if(content_disposition==null)
123             {
124                 throw new IOException JavaDoc("Missing content-disposition");
125             }
126             
127             StringTokenizer JavaDoc tok=new StringTokenizer JavaDoc(content_disposition,";");
128             String JavaDoc name=null;
129             String JavaDoc filename=null;
130             while(tok.hasMoreTokens())
131             {
132                 String JavaDoc t=tok.nextToken().trim();
133                 String JavaDoc tl=t.toLowerCase();
134                 if(t.startsWith("form-data"))
135                     form_data=true;
136                 else if(tl.startsWith("name="))
137                     name=value(t);
138                 else if(tl.startsWith("filename="))
139                     filename=value(t);
140             }
141             
142             // Check disposition
143
if(!form_data)
144             {
145                 log.warn("Non form-data part in multipart/form-data");
146                 continue;
147             }
148             if(name==null||name.length()==0)
149             {
150                 log.warn("Part with no name in multipart/form-data");
151                 continue;
152             }
153             
154             OutputStream JavaDoc out=null;
155             File JavaDoc file=null;
156             try
157             {
158                 if (filename!=null && filename.length()>0)
159                 {
160                     file = File.createTempFile("MultiPart", "", tempdir);
161                     out = new FileOutputStream JavaDoc(file);
162                     request.setAttribute(name,file);
163                     params.put(name, filename);
164                 }
165                 else
166                     out=new ByteArrayOutputStream JavaDoc();
167                 
168                 int state=-2;
169                 int c;
170                 boolean cr=false;
171                 boolean lf=false;
172                 
173                 // loop for all lines`
174
while(true)
175                 {
176                     int b=0;
177                     while((c=(state!=-2)?state:in.read())!=-1)
178                     {
179                         state=-2;
180                         // look for CR and/or LF
181
if(c==13||c==10)
182                         {
183                             if(c==13)
184                                 state=in.read();
185                             break;
186                         }
187                         // look for boundary
188
if(b>=0&&b<byteBoundary.length&&c==byteBoundary[b])
189                             b++;
190                         else
191                         {
192                             // this is not a boundary
193
if(cr)
194                                 out.write(13);
195                             if(lf)
196                                 out.write(10);
197                             cr=lf=false;
198                             if(b>0)
199                                 out.write(byteBoundary,0,b);
200                             b=-1;
201                             out.write(c);
202                         }
203                     }
204                     // check partial boundary
205
if((b>0&&b<byteBoundary.length-2)||(b==byteBoundary.length-1))
206                     {
207                         if(cr)
208                             out.write(13);
209                         if(lf)
210                             out.write(10);
211                         cr=lf=false;
212                         out.write(byteBoundary,0,b);
213                         b=-1;
214                     }
215                     // boundary match
216
if(b>0||c==-1)
217                     {
218                         if(b==byteBoundary.length)
219                             lastPart=true;
220                         if(state==10)
221                             state=-2;
222                         break;
223                     }
224                     // handle CR LF
225
if(cr)
226                         out.write(13);
227                     if(lf)
228                         out.write(10);
229                     cr=(c==13);
230                     lf=(c==10||state==10);
231                     if(state==10)
232                         state=-2;
233                 }
234             }
235             finally
236             {
237                 IO.close(out);
238             }
239             
240             if (file==null)
241             {
242                 byte[] bytes = ((ByteArrayOutputStream JavaDoc)out).toByteArray();
243                 params.add(name,bytes);
244             }
245         }
246
247         chain.doFilter(new Wrapper JavaDoc(srequest,params),response);
248         
249         // TODO delete the files if they still exist.
250
}
251
252
253     /* ------------------------------------------------------------ */
254     private String JavaDoc value(String JavaDoc nameEqualsValue)
255     {
256         String JavaDoc value=nameEqualsValue.substring(nameEqualsValue.indexOf('=')+1).trim();
257         int i=value.indexOf(';');
258         if(i>0)
259             value=value.substring(0,i);
260         if(value.startsWith("\""))
261         {
262             value=value.substring(1,value.indexOf('"',1));
263         }
264         else
265         {
266             i=value.indexOf(' ');
267             if(i>0)
268                 value=value.substring(0,i);
269         }
270         return value;
271     }
272
273     /* ------------------------------------------------------------------------------- */
274     /**
275      * @see javax.servlet.Filter#destroy()
276      */

277     public void destroy()
278     {
279     }
280     
281     private static class Wrapper extends HttpServletRequestWrapper JavaDoc
282     {
283         String JavaDoc encoding="UTF-8";
284         MultiMap map;
285         
286         /* ------------------------------------------------------------------------------- */
287         /** Constructor.
288          * @param request
289          */

290         public Wrapper(HttpServletRequest JavaDoc request, MultiMap map)
291         {
292             super(request);
293             this.map=map;
294         }
295         
296         /* ------------------------------------------------------------------------------- */
297         /**
298          * @see javax.servlet.ServletRequest#getContentLength()
299          */

300         public int getContentLength()
301         {
302             return 0;
303         }
304         
305         /* ------------------------------------------------------------------------------- */
306         /**
307          * @see javax.servlet.ServletRequest#getParameter(java.lang.String)
308          */

309         public String JavaDoc getParameter(String JavaDoc name)
310         {
311             Object JavaDoc o=map.get(name);
312             if (o instanceof byte[])
313             {
314                 try
315                 {
316                     String JavaDoc s=new String JavaDoc((byte[])o,encoding);
317                     return s;
318                 }
319                 catch(Exception JavaDoc e)
320                 {
321                     log.warn(e);
322                 }
323             }
324             else if (o instanceof String JavaDoc)
325                 return (String JavaDoc)o;
326             return null;
327         }
328         
329         /* ------------------------------------------------------------------------------- */
330         /**
331          * @see javax.servlet.ServletRequest#getParameterMap()
332          */

333         public Map JavaDoc getParameterMap()
334         {
335             return map;
336         }
337         
338         /* ------------------------------------------------------------------------------- */
339         /**
340          * @see javax.servlet.ServletRequest#getParameterNames()
341          */

342         public Enumeration JavaDoc getParameterNames()
343         {
344             return Collections.enumeration(map.keySet());
345         }
346         
347         /* ------------------------------------------------------------------------------- */
348         /**
349          * @see javax.servlet.ServletRequest#getParameterValues(java.lang.String)
350          */

351         public String JavaDoc[] getParameterValues(String JavaDoc name)
352         {
353             List JavaDoc l=map.getValues(name);
354             if (l==null || l.size()==0)
355                 return new String JavaDoc[0];
356             String JavaDoc[] v = new String JavaDoc[l.size()];
357             for (int i=0;i<l.size();i++)
358             {
359                 Object JavaDoc o=l.get(i);
360                 if (o instanceof byte[])
361                 {
362                     try
363                     {
364                         v[i]=new String JavaDoc((byte[])o,encoding);
365                     }
366                     catch(Exception JavaDoc e)
367                     {
368                         log.warn(e);
369                     }
370                 }
371                 else if (o instanceof String JavaDoc)
372                     v[i]=(String JavaDoc)o;
373             }
374             return v;
375         }
376         
377         /* ------------------------------------------------------------------------------- */
378         /**
379          * @see javax.servlet.ServletRequest#setCharacterEncoding(java.lang.String)
380          */

381         public void setCharacterEncoding(String JavaDoc enc)
382             throws UnsupportedEncodingException JavaDoc
383         {
384             encoding=enc;
385         }
386     }
387 }
388
Popular Tags