KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jodd > servlet > MultipartRequest


1 package jodd.servlet;
2
3 import java.io.IOException;
4 import java.io.UnsupportedEncodingException;
5 import java.util.ArrayList;
6 import java.util.Enumeration;
7 import java.util.Hashtable;
8
9 import javax.servlet.http.HttpServletRequest;
10
11 /**
12  * Handles multipart requests and extract uploaded files and parameters from
13  * it. Multipart forms should be defined as:
14  * <p>
15  *
16  * <code>
17  * &lt;form method="post" enctype="multipart/form-data" accept-charset="<i>charset</i>"...
18  * </code>
19  *
20  * <p>
21  * "accept-charset" should be used in case when jsp page uses specific
22  * encoding. If dfault encoding is used, this attribute is not required.
23  *
24  * <p>
25  * This class loads complete request. To prevent big uploads (and potential
26  * DoS attacks) check content length <b>before</b> using this class.
27  */

28 public class MultipartRequest {
29
30     private Hashtable requestParameters;
31
32     private Hashtable requestFiles;
33
34     /**
35      * Default constructor, for using MultipartRequest in steps.
36      */

37     public MultipartRequest() {
38     }
39
40     /**
41      * Constructor that loads request and extracts all uploaded files and
42      * parameters using specified encoding. If request is not multipart, all
43      * parameters will be read, anyway.
44      *
45      * @param request http request
46      * @param encoding encoding
47      *
48      * @exception IOException
49      */

50     public MultipartRequest(HttpServletRequest request, String encoding) throws IOException {
51         load(request, encoding);
52     }
53
54     /**
55      * Constructor that loads request and extracts all uploaded files and
56      * parameters without encoding.
57      *
58      * @param request http request
59      *
60      * @exception IOException
61      * @see #MultipartRequest(HttpServletRequest, String)
62      */

63
64     public MultipartRequest(HttpServletRequest request) throws IOException {
65         load(request);
66     }
67
68
69     /**
70      * Loads http request manually without encoding.
71      *
72      * @param request http request.
73      *
74      * @exception IOException
75      * @see #load(HttpServletRequest, String)
76      */

77     public void load(HttpServletRequest request) throws IOException {
78         load(request, null);
79     }
80
81     /**
82      * Loads http request manually, with susing of specific encoding. If request
83      * is not multipart, all parameters will be read, anyway.
84      *
85      * @param request http request.
86      * @param encoding encoding that will be used during extracting
87      *
88      * @exception IOException
89      */

90     public void load(HttpServletRequest request, String encoding) throws IOException {
91
92         if (ServletUtil.isRequestMultipart(request) == true) {
93             byte[] requestData = getRequestData(request);
94             Hashtable[] maps = extractParameters(requestData, encoding);
95             requestParameters = maps[0];
96             requestFiles = maps[1];
97         } else {
98             requestParameters = new Hashtable();
99             requestFiles = new Hashtable();
100             Enumeration names = request.getParameterNames();
101             while (names.hasMoreElements()) {
102                 String paramName = (String) names.nextElement();
103                 String[] values = request.getParameterValues(paramName);
104                 requestParameters.put(paramName, values);
105             }
106         }
107     }
108
109
110     /**
111      * Returns value of a parameter.
112      *
113      * @param paramName parameter name
114      *
115      * @return parameer value, or <code>null</code> if not found
116      */

117     public String getParameter(String paramName) {
118         String[] values = (String[]) requestParameters.get(paramName);
119         if ((values != null) && (values.length > 0)) {
120             return (String) values[0];
121         }
122         return null;
123     }
124     /**
125      * Returns names of all availiable parameters.
126      *
127      * @return enumeration of all parameters names
128      */

129     public Enumeration getParameterNames() {
130         return requestParameters.keys();
131     }
132
133     public String[] getParameterValues(String paramName) {
134         return (String[]) requestParameters.get(paramName);
135     }
136
137
138     /**
139      * Returns uploaded file.
140      *
141      * @param paramName parameter name of the uploaded file
142      *
143      * @return uploaded file or <code>null</code> if parameter name not found
144      */

145     public UploadedFile getUploadedFile(String paramName) {
146         return (UploadedFile) requestFiles.get(paramName);
147     }
148
149     /**
150      * Returns parameter names of all uploaded files.
151      *
152      * @return enumeration of all uploaded files parameter names
153      */

154     public Enumeration getUploadedFileNames() {
155         return requestFiles.keys();
156     }
157
158
159     // ---------------------------------------------------------------- load and extract
160

161     /**
162      * Loads request data into a byte array.
163      *
164      * @param request http request
165      *
166      * @return byte array containing request data
167      * @exception IOException
168      */

169     public static byte[] getRequestData(HttpServletRequest request) throws IOException {
170         int totalBytes = request.getContentLength();
171         byte[] binArray = new byte[totalBytes];
172         int readBytes = 0;
173         try {
174             for (int totalRead = 0; totalRead < totalBytes; totalRead += readBytes) {
175                 readBytes = request.getInputStream().read(binArray, totalRead, totalBytes - totalRead);
176             }
177         } catch (Exception e) {
178             throw new IOException("Upload error.");
179         }
180         return binArray;
181     }
182
183     /**
184      * Extracts uploaded files and parameters from the request data, not using
185      * any encoding.
186      *
187      * @param binArray binarry array of loaded request data
188      *
189      * @return array with two Hashtables that contains parameters and uploaded files
190      * @see #getRequestData
191      * @see #extractParameters(byte[], String)
192      */

193     public static Hashtable[] extractParameters(byte[] binArray) {
194         return extractParameters(binArray, null);
195     }
196
197     /**
198      * Extracts uploaded files and parameters from the request data. The result
199      * is returned as array of two Hashtables. The first one contains parameter
200      * data, and the second one contains uploaded file data.
201      *
202      * @param binArray binarry array of loaded request data
203      * @param encoding encoding for parameters, if <code>null</code> encoding will not be used
204      *
205      * @return array with two Hashtables that contains parameters and uploaded files
206      * @see #getRequestData
207      */

208     public static Hashtable[] extractParameters(byte[] binArray, String encoding) {
209         if (binArray == null) {
210             return null;
211         }
212         Hashtable parameters = new Hashtable();
213         Hashtable files = new Hashtable();
214         int totalBytes = binArray.length;
215         int currentIndex = 0;
216         StringBuffer boundary = new StringBuffer();
217         while (currentIndex < totalBytes) {
218             if (binArray[currentIndex] == 13) {
219                 break;
220             }
221             boundary.append((char)binArray[currentIndex]);
222             currentIndex++;
223         }
224         if (currentIndex == 1) {
225             return null;
226         }
227         currentIndex++;
228
229         while (currentIndex < totalBytes) {
230             
231             /* data header */
232             int start = currentIndex;
233             String dataHeader = null;
234             while (currentIndex < totalBytes) {
235                 if ((binArray[currentIndex] == 13) && (binArray[currentIndex + 2] == 13)) {
236                     int end = currentIndex;
237                     if (encoding != null) {
238                         try {
239                             dataHeader = new String(binArray, start, currentIndex - start, encoding);
240                         } catch (UnsupportedEncodingException ueex) {
241                             dataHeader = null;
242                         }
243                     }
244                     if (dataHeader == null) {
245                         dataHeader = new String(binArray, start, currentIndex - start);
246                     }
247                     currentIndex += 2;
248                     break;
249                 }
250                 currentIndex++;
251             }
252             if (dataHeader == null) {
253                 break;
254             }
255             currentIndex += 2;
256             boolean isFile = dataHeader.indexOf("filename") > 0;
257
258             /* fields */
259             String fieldName = getDataFieldValue(dataHeader, "name");
260             String fileName = "";
261             String filePathName = "";
262             if (isFile) {
263                 filePathName = getDataFieldValue(dataHeader, "filename");
264                 fileName = getFileName(filePathName);
265             }
266
267             /* data section */
268             boolean found = false;
269             int searchPos = currentIndex;
270             int keyPos = 0;
271             int boundaryLen = boundary.length();
272             int startData = currentIndex;
273             int endData = 0;
274             while (true) {
275                 if (searchPos >= totalBytes) break;
276                 if (binArray[searchPos] == (byte) boundary.charAt(keyPos)) {
277                     if (keyPos == boundaryLen - 1) {
278                         endData = ((searchPos - boundaryLen) + 1) - 3;
279                         break;
280                     }
281                     searchPos++;
282                     keyPos++;
283                 } else {
284                     searchPos++;
285                     keyPos = 0;
286                 }
287             }
288             currentIndex = endData + boundaryLen + 3;
289
290             /* store file */
291             if (isFile && (fileName.length() > 0)) {
292                 int totalFileSize = (endData - startData) + 1;
293                 UploadedFile newFile = new UploadedFile();
294                 newFile.setFieldName(fieldName);
295                 newFile.setFilePathName(filePathName);
296                 String contentType = getContentType(dataHeader);
297                 newFile.setContentType(contentType);
298                 newFile.setContentDisp(getContentDisp(dataHeader));
299                 if (contentType.indexOf("application/x-macbinary") > 0) {
300                     startData += 128;
301                 }
302                 newFile.setSize((endData - startData) + 1);
303                 newFile.setDataStart(startData);
304                 //newFile.setDataEnd(endData);
305
newFile.setRequestData(binArray);
306                 
307                 files.put(fieldName, newFile);
308             } else {
309                 String value = null;
310                 if (encoding != null) {
311                     try {
312                         value = new String(binArray, startData, (endData - startData) + 1, encoding);
313                     } catch (UnsupportedEncodingException ucex) {
314                         value = null;
315                     }
316                 }
317                 if (value == null) {
318                     value = new String(binArray, startData, (endData - startData) + 1);
319                 }
320                 if (isFile == false) {
321                     ArrayList valuesList = (ArrayList) parameters.get(fieldName);
322                     if (valuesList == null) {
323                         valuesList = new ArrayList();
324                     }
325                     valuesList.add(value);
326                     parameters.put(fieldName, valuesList);
327                 } else {
328                     UploadedFile newFile = new UploadedFile(false);
329                     newFile.setFieldName(fieldName);
330                     newFile.setFilePathName(value);
331                     files.put(fieldName, newFile);
332                 }
333             }
334             if ((char)binArray[currentIndex + 1] == '-') {
335                 break;
336             }
337             currentIndex += 2;
338         }
339
340         // convert ArrayLists for parameters into arrays
341
Enumeration names = parameters.keys();
342         while (names.hasMoreElements()) {
343             String paramName = (String) names.nextElement();
344             ArrayList valuesList = (ArrayList) parameters.get(paramName);
345             if (valuesList != null) {
346                 String[] result = new String[valuesList.size()];
347                 for (int i = 0; i < result.length; i++) {
348                     result[i] = (String) valuesList.get(i);
349                 }
350                 parameters.put(paramName, result);
351             }
352         }
353         return new Hashtable[] {parameters, files};
354     }
355
356
357
358     // ---------------------------------------------------------------- misc utils
359

360     /**
361      * Gets value of data field
362      *
363      * @param dataHeader header
364      * @param fieldName field's name
365      *
366      * @return value or empty string if not founded
367      */

368     public static String getDataFieldValue(String dataHeader, String fieldName) {
369         String value = "";
370         String token = String.valueOf((new StringBuffer(String.valueOf(fieldName))).append("=").append('"'));
371         int pos = dataHeader.indexOf(token);
372         if (pos > 0) {
373             int i = pos + token.length();
374             int start = i;
375             token = "\"";
376             int end = dataHeader.indexOf(token, i);
377             if ((start > 0) && (end > 0)) {
378                 value = dataHeader.substring(start, end);
379             }
380         }
381         return value;
382     }
383
384     /**
385      * Strips content type information from request's data header.
386      *
387      * @param dataHeader data header string
388      *
389      * @return content type or an empty string if no content type defined
390      */

391     private static String getContentType(String dataHeader) {
392         String token = "Content-Type:";
393         int start = dataHeader.indexOf(token);
394         if (start == -1) {
395             return "";
396         }
397         start += token.length();
398         return dataHeader.substring(start);
399     }
400
401     private static String getFileName(String filePathName) {
402         int pos = filePathName.lastIndexOf('/');
403         if (pos != -1) {
404             return filePathName.substring(pos + 1);
405         }
406         pos = filePathName.lastIndexOf('\\');
407         if (pos != -1) {
408             return filePathName.substring(pos + 1);
409         }
410         return filePathName;
411     }
412
413     private static String getContentDisp(String dataHeader) {
414         int start = dataHeader.indexOf(":") + 1;
415         int end = dataHeader.indexOf(";");
416         return dataHeader.substring(start, end);
417     }
418
419
420 }
421
Popular Tags