KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > jac > aspects > gui > web > MultiPartRequest


1 // ========================================================================
2
// Copyright (c) 1996 Mort Bay Consulting Pty. Ltd. All rights reserved.
3
// $Id: MultiPartRequest.java,v 1.6 2004/03/29 12:52:09 laurent Exp $
4
// ------------------------------------------------------------------------
5

6 package org.objectweb.jac.aspects.gui.web;
7
8 import java.io.ByteArrayInputStream JavaDoc;
9 import java.io.ByteArrayOutputStream JavaDoc;
10 import java.io.IOException JavaDoc;
11 import java.io.InputStream JavaDoc;
12 import java.io.UnsupportedEncodingException JavaDoc;
13 import java.util.Hashtable JavaDoc;
14 import java.util.List JavaDoc;
15 import java.util.StringTokenizer JavaDoc;
16 import javax.servlet.http.HttpServletRequest JavaDoc;
17 import org.apache.log4j.Logger;
18 import org.mortbay.http.HttpFields;
19 import org.mortbay.util.Code;
20 import org.mortbay.util.LineInput;
21 import org.mortbay.util.MultiMap;
22 import org.mortbay.util.StringUtil;
23 import org.objectweb.jac.util.ExtArrays;
24
25 /* ------------------------------------------------------------ */
26 /** Multipart Form Data request.
27  * <p>
28  * This class decodes the multipart/form-data stream sent by
29  * a HTML form that uses a file input item.
30  *
31  * <p><h4>Usage</h4>
32  * Each part of the form data is named from the HTML form and
33  * is available either via getString(name) or getInputStream(name).
34  * Furthermore the MIME parameters and filename can be requested for
35  * each part.
36  * <pre>
37  * </pre>
38  *
39  * @version $Id: MultiPartRequest.java,v 1.6 2004/03/29 12:52:09 laurent Exp $
40  * @author Greg Wilkins
41  * @author Jim Crossley
42  */

43 public class MultiPartRequest
44 {
45     static Logger logger = Logger.getLogger("web.servlet");
46
47     /* ------------------------------------------------------------ */
48     HttpServletRequest JavaDoc _request;
49     LineInput _in;
50     String JavaDoc _boundary;
51     byte[] _byteBoundary;
52     MultiMap _partMap = new MultiMap(10);
53     int _char = -2;
54     boolean _lastPart = false;
55     String JavaDoc _enc = StringUtil.__ISO_8859_1;
56
57     /* ------------------------------------------------------------ */
58     /** Constructor.
59      * @param request The request containing a multipart/form-data
60      * request
61      * @param enc the encoding of characters
62      * @exception IOException IOException
63      */

64     public MultiPartRequest(HttpServletRequest JavaDoc request, String JavaDoc enc)
65         throws IOException JavaDoc
66     {
67         _request=request;
68         _enc = enc;
69         String JavaDoc content_type = request.getHeader(HttpFields.__ContentType);
70         if (!content_type.startsWith("multipart/form-data"))
71             throw new IOException JavaDoc("Not multipart/form-data request");
72
73         Code.debug("Multipart content type = ",content_type);
74         
75         _in = new LineInput(request.getInputStream());
76         
77         // Extract boundary string
78
_boundary="--"+
79             value(content_type.substring(content_type.indexOf("boundary=")));
80         
81         Code.debug("Boundary=",_boundary);
82         _byteBoundary= (_boundary+"--").getBytes(StringUtil.__ISO_8859_1);
83         
84         loadAllParts();
85     }
86
87     protected Part getPart(String JavaDoc name) {
88        Object JavaDoc part = _partMap.get(name);
89        if (part instanceof List)
90           return (Part)((List)part).get(0);
91        else
92           return (Part)part;
93     }
94
95     /* ------------------------------------------------------------ */
96     /** Get the part names.
97      * @return an array of part names
98      */

99     public String JavaDoc[] getPartNames()
100     {
101         return (String JavaDoc[]) _partMap.keySet().toArray(ExtArrays.emptyStringArray);
102     }
103     
104     /* ------------------------------------------------------------ */
105     /** Check if a named part is present
106      * @param name The part
107      * @return true if it was included
108      */

109     public boolean contains(String JavaDoc name)
110     {
111         Part part = (Part)_partMap.get(name);
112         return (part!=null);
113     }
114     
115     /* ------------------------------------------------------------ */
116     /** Get the data of a part as a string.
117      * @param name The part name
118      * @return The part data
119      */

120     public String JavaDoc getString(String JavaDoc name)
121     {
122         List part = (List)_partMap.getValues(name);
123         if (part==null)
124             return null;
125         return decodeString(((Part)part.get(0))._data);
126     }
127     
128     /* ------------------------------------------------------------ */
129     /**
130      * @param name The part name
131      * @return The parts data
132      */

133     public String JavaDoc[] getStrings(String JavaDoc name)
134     {
135         List parts = (List)_partMap.getValues(name);
136         if (parts==null)
137             return null;
138         String JavaDoc[] strings = new String JavaDoc[parts.size()];
139         for (int i=0; i<strings.length; i++) {
140             strings[i] = decodeString(((Part)parts.get(i))._data);
141         }
142         return strings;
143     }
144
145     protected String JavaDoc decodeString(byte[] bytes) {
146         try {
147             return new String JavaDoc(bytes,_enc);
148         } catch (UnsupportedEncodingException JavaDoc e) {
149             logger.error("Unsupported encoding: "+_enc);
150             return new String JavaDoc(bytes);
151         }
152     }
153     
154     /* ------------------------------------------------------------ */
155     /** Get the data of a part as a stream.
156      * @param name The part name
157      * @return Stream providing the part data
158      */

159     public InputStream JavaDoc getInputStream(String JavaDoc name)
160     {
161         Part part = getPart(name);
162         if (part==null)
163             return null;
164         else
165            return new ByteArrayInputStream JavaDoc(part._data);
166     }
167
168     public InputStream JavaDoc[] getInputStreams(String JavaDoc name)
169     {
170         List parts = (List)_partMap.getValues(name);
171         if (parts==null)
172             return null;
173         InputStream JavaDoc[] streams = new InputStream JavaDoc[parts.size()];
174         for (int i=0; i<streams.length; i++) {
175             streams[i] = new ByteArrayInputStream JavaDoc(((Part)parts.get(i))._data);
176         }
177         return streams;
178     }
179
180     /* ------------------------------------------------------------ */
181     /** Get the MIME parameters associated with a part.
182      * @param name The part name
183      * @return Hashtable of parameters
184      */

185     public Hashtable JavaDoc getParams(String JavaDoc name)
186     {
187         List part = (List)_partMap.getValues(name);
188         if (part==null)
189             return null;
190         return ((Part)part.get(0))._headers;
191     }
192
193     public Hashtable JavaDoc[] getMultipleParams(String JavaDoc name)
194     {
195         List parts = (List)_partMap.getValues(name);
196         if (parts==null)
197             return null;
198         Hashtable JavaDoc[] params = new Hashtable JavaDoc[parts.size()];
199         for (int i=0; i<params.length; i++) {
200             params[i] = ((Part)parts.get(i))._headers;
201         }
202         return params;
203     }
204
205     /* ------------------------------------------------------------ */
206     /** Get any file name associated with a part.
207      * @param name The part name
208      * @return The filename
209      */

210     public String JavaDoc getFilename(String JavaDoc name)
211     {
212         List part = (List)_partMap.getValues(name);
213         if (part==null)
214             return null;
215         return ((Part)part.get(0))._filename;
216     }
217
218     public String JavaDoc[] getFilenames(String JavaDoc name)
219     {
220         List parts = (List)_partMap.getValues(name);
221         if (parts==null)
222             return null;
223         String JavaDoc[] filenames = new String JavaDoc[parts.size()];
224         for (int i=0; i<filenames.length; i++) {
225             filenames[i] = ((Part)parts.get(i))._filename;
226         }
227         return filenames;
228     }
229
230     /* ------------------------------------------------------------ */
231     private void loadAllParts()
232         throws IOException JavaDoc
233     {
234         // Get first boundary
235
String JavaDoc line = _in.readLine();
236         if (!line.equals(_boundary))
237         {
238             Code.warning(line);
239             throw new IOException JavaDoc("Missing initial multi part boundary");
240         }
241         
242         // Read each part
243
while (!_lastPart)
244         {
245             // Read Part headers
246
Part part = new Part();
247             
248             String JavaDoc content_disposition=null;
249             while ((line=_in.readLine())!=null)
250             {
251                 // If blank line, end of part headers
252
if (line.length()==0)
253                     break;
254
255                 Code.debug("LINE=",line);
256                 
257                 // place part header key and value in map
258
int c = line.indexOf(':',0);
259                 if (c>0)
260                 {
261                     String JavaDoc key = line.substring(0,c).trim().toLowerCase();
262                     String JavaDoc value = line.substring(c+1,line.length()).trim();
263                     String JavaDoc ev = (String JavaDoc) part._headers.get(key);
264                     part._headers.put(key,(ev!=null)?(ev+';'+value):value);
265                     Code.debug(key,": ",value);
266                     if (key.equals("content-disposition"))
267                         content_disposition=value;
268                 }
269             }
270
271             // Extract content-disposition
272
boolean form_data=false;
273             if (content_disposition==null)
274             {
275                 throw new IOException JavaDoc("Missing content-disposition");
276             }
277             
278             StringTokenizer JavaDoc tok =
279                 new StringTokenizer JavaDoc(content_disposition,";");
280             while (tok.hasMoreTokens())
281             {
282                 String JavaDoc t = tok.nextToken().trim();
283                 String JavaDoc tl = t.toLowerCase();
284                 if (t.startsWith("form-data"))
285                     form_data=true;
286                 else if (tl.startsWith("name="))
287                     part._name=value(t);
288                 else if (tl.startsWith("filename="))
289                     part._filename=value(t);
290             }
291
292             // Check disposition
293
if (!form_data)
294             {
295                 Code.warning("Non form-data part in multipart/form-data");
296                 continue;
297             }
298             if (part._name==null || part._name.length()==0)
299             {
300                 Code.warning("Part with no name in multipart/form-data");
301                 continue;
302             }
303             Code.debug("name=",part._name);
304             Code.debug("filename=",part._filename);
305             _partMap.add(part._name,part);
306             part._data=readBytes();
307         }
308     }
309
310     /* ------------------------------------------------------------ */
311     private byte[] readBytes()
312         throws IOException JavaDoc
313     {
314         ByteArrayOutputStream JavaDoc baos = new ByteArrayOutputStream JavaDoc();
315
316         int c;
317         boolean cr=false;
318         boolean lf=false;
319         
320         // loop for all lines`
321
while (true)
322         {
323             int b=0;
324             while ((c=(_char!=-2)?_char:_in.read())!=-1)
325             {
326                 _char=-2;
327
328                 // look for CR and/or LF
329
if (c==13 || c==10)
330                 {
331                     if (c==13) _char=_in.read();
332                     break;
333                 }
334
335                 // look for boundary
336
if (b>=0 && b<_byteBoundary.length && c==_byteBoundary[b])
337                     b++;
338                 else
339                 {
340                     // this is not a boundary
341
if (cr) baos.write(13);
342                     if (lf) baos.write(10);
343                     cr=lf=false;
344                     
345                     if (b>0)
346                         baos.write(_byteBoundary,0,b);
347                     b=-1;
348                   
349                     baos.write(c);
350                 }
351             }
352
353             // check partial boundary
354
if ((b>0 && b<_byteBoundary.length-2) ||
355                 (b==_byteBoundary.length-1))
356             {
357                 if (cr) baos.write(13);
358                 if (lf) baos.write(10);
359                 cr=lf=false;
360                 baos.write(_byteBoundary,0,b);
361                 b=-1;
362             }
363             
364             // boundary match
365
if (b>0 || c==-1)
366             {
367                 if (b==_byteBoundary.length)
368                     _lastPart=true;
369                 if (_char==10) _char=-2;
370                 break;
371             }
372             
373             // handle CR LF
374
if (cr) baos.write(13);
375             if (lf) baos.write(10);
376             cr=(c==13);
377             lf=(c==10 || _char==10);
378             if (_char==10) _char=-2;
379         }
380         if (Code.verbose()) Code.debug(baos.toString());
381         return baos.toByteArray();
382     }
383     
384     
385     /* ------------------------------------------------------------ */
386     private String JavaDoc value(String JavaDoc nameEqualsValue)
387     {
388         String JavaDoc value =
389             nameEqualsValue.substring(nameEqualsValue.indexOf('=')+1).trim();
390         
391         int i=value.indexOf(';');
392         if (i>0)
393             value=value.substring(0,i);
394         if (value.startsWith("\""))
395         {
396             value=value.substring(1,value.indexOf('"',1));
397         }
398         
399         else
400         {
401             i=value.indexOf(' ');
402             if (i>0)
403                 value=value.substring(0,i);
404         }
405         return value;
406     }
407     
408     /* ------------------------------------------------------------ */
409     private class Part
410     {
411         String JavaDoc _name=null;
412         String JavaDoc _filename=null;
413         Hashtable JavaDoc _headers= new Hashtable JavaDoc(10);
414         byte[] _data=null;
415     }
416 };
417
Popular Tags