1 package org.apache.turbine.util.upload;
2
3 /* ====================================================================
4 * The Apache Software License, Version 1.1
5 *
6 * Copyright (c) 2001 The Apache Software Foundation. All rights
7 * reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
19 * distribution.
20 *
21 * 3. The end-user documentation included with the redistribution,
22 * if any, must include the following acknowledgment:
23 * "This product includes software developed by the
24 * Apache Software Foundation (http://www.apache.org/)."
25 * Alternately, this acknowledgment may appear in the software itself,
26 * if and wherever such third-party acknowledgments normally appear.
27 *
28 * 4. The names "Apache" and "Apache Software Foundation" and
29 * "Apache Turbine" must not be used to endorse or promote products
30 * derived from this software without prior written permission. For
31 * written permission, please contact apache@apache.org.
32 *
33 * 5. Products derived from this software may not be called "Apache",
34 * "Apache Turbine", nor may "Apache" appear in their name, without
35 * prior written permission of the Apache Software Foundation.
36 *
37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
41 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48 * SUCH DAMAGE.
49 * ====================================================================
50 *
51 * This software consists of voluntary contributions made by many
52 * individuals on behalf of the Apache Software Foundation. For more
53 * information on the Apache Software Foundation, please see
54 * <http://www.apache.org/>.
55 */
56
57 import java.io.BufferedInputStream;
58 import java.io.BufferedOutputStream;
59 import java.io.File;
60 import java.io.FileInputStream;
61 import java.io.FileOutputStream;
62 import java.io.IOException;
63 import java.io.InputStream;
64 import java.io.OutputStream;
65 import java.lang.reflect.Method;
66 import java.util.Date;
67 import javax.servlet.ServletException;
68 import javax.servlet.http.HttpServletRequest;
69 import javax.servlet.http.HttpServletResponse;
70 import org.apache.turbine.util.ParameterParser;
71 import org.apache.turbine.util.RunData;
72
73 /***
74 * This class is used to upload files from a client to the server (any
75 * types and any number of fields is supported) and download files
76 * from the server to the client.
77 *
78 * @author <a href="mailto:oleg@one.lv">Oleg M. Podolsky</a>
79 * @author <a href="mailto:neeme@one.lv">Neeme Praks</a>
80 *
81 * @deprecated Use TurbineUploadService counterpart FileItem.
82 */
83 public class FileHandler
84 {
85 public static String PARAMETER_NAME_FILENAME = "_fileuploader_filename";
86 public static String PARAMETER_NAME_FILESIZE = "_fileuploader_filesize";
87 public static String PARAMETER_NAME_FILENAME_SAVED = "_fileuploader_filename_saved";
88 public static String PARAMETER_NAME_ENCODING = "_fileuploader_encoding";
89 public static String PARAMETER_NAME_CONTENT_TYPE = "_fileuploader_content-type";
90
91 /*** Carriage return - line feed two times. */
92 private static final byte[] CRLF2 = { 0xD, 0xA, 0xD, 0xA };
93
94 /***
95 * Buffer for reading/writing data and buffer for storing all
96 * data.
97 */
98 private static int readbuffersize = 4096;
99 private byte[] readbuffer = new byte[readbuffersize];
100 private int storebuffersize;
101 private byte[] storebuffer = null;
102
103 /*** Buffer for sending data back to browser. */
104 private static int writebuffersize = 4096;
105 private byte[] writebuffer = new byte[writebuffersize];
106
107 /*** Maximum number of bytes accepted, if zero then no limit. */
108 private long maxdata = 0;
109
110 /*** Place for boundary that separates field data. */
111 private int boundarysize;
112 private byte[] boundary = null;
113
114 private String fieldname, filename, contenttype;
115
116 private HttpServletRequest req;
117 private HttpServletResponse res;
118 private ParameterParser pp;
119 private String root;
120
121 /***
122 * If the form data is non-multipart (simple), it returns true,
123 * otherwise returns false.
124 *
125 * @param req An HttpServletRequest.
126 * @return True if the form data is non-multipart (simple).
127 * @deprecated Use TurbineUploadService counterpart FileItem.
128 */
129 public static boolean isSimpleForm(HttpServletRequest req)
130 {
131 String header = req.getHeader("Content-Type");
132 if (header != null && header.indexOf("multipart/form-data") >= 0)
133 {
134 return false;
135 }
136 return true;
137 }
138
139 /***
140 * Copies stream ins to stream outs.
141 *
142 * @param ins An InputStream.
143 * @param outs An OutputStream.
144 * @exception IOException.
145 */
146 private void copyStream(InputStream ins,
147 OutputStream outs)
148 throws IOException
149 {
150 BufferedInputStream bis = new BufferedInputStream(ins, writebuffersize);
151 BufferedOutputStream bos
152 = new BufferedOutputStream(outs, writebuffersize);
153 int bufread;
154
155 while ((bufread = bis.read(writebuffer)) != -1)
156 {
157 bos.write(writebuffer, 0, bufread);
158 }
159 bos.flush(); bos.close();
160 bis.close();
161 }
162
163 /***
164 * Writes HTTP headers and the file data to the response.
165 *
166 * @param savedname A String.
167 * @param filename A String.
168 * @param contenttype A String.
169 * @exception Exception, a generic exception.
170 * @deprecated Use TurbineUploadService counterpart FileItem.
171 */
172 public void writeFileToResponse(String savedname,
173 String filename,
174 String contenttype)
175 throws Exception
176 {
177 String fullPath = root + "/" + savedname;
178 File f = new File(fullPath);
179
180 // The following try block replaces:
181 // res.setBufferSize(writebuffersize);
182 try
183 {
184 Class[] sig = new Class[1];
185 sig[0] = Integer.TYPE;
186 Object[] param = new Object[1];
187 param[0] = new Integer(writebuffersize);
188 Method method = res.getClass()
189 .getDeclaredMethod("setBufferSize", sig);
190 method.invoke(res, param);
191 }
192 catch (Exception e)
193 {
194 // Ignore it.
195 }
196 res.setContentLength((int)f.length());
197 res.setContentType(contenttype);
198 res.setHeader("Content-Disposition",
199 "attachment; filename=\"" + filename + "\"");
200 res.setDateHeader("Date", new Date().getTime());
201 res.setDateHeader("Expires", new Date().getTime());
202 res.setIntHeader("Age",0);
203 res.setIntHeader("Retry-After",60);
204 res.setHeader("Pragma","no-cache");
205 res.setHeader("Connection","Keep-Alive");
206
207 copyStream(new FileInputStream(fullPath), res.getOutputStream());
208 }
209
210 /***
211 * Finds random name in the ROOT directory. For example, if
212 * ROOT="c:/temp", name="c:/temp/upload23967879053.dat". ROOT
213 * cannot finish with '/' or '\'.
214 *
215 * @return A String with a random name in the given directory.
216 */
217 private String getRandomName()
218 {
219 // TODO: if user is logged in, then put the file in user's
220 // folder.
221 String name = null;
222 String fullpath = null;
223 File f = null;
224
225 do
226 {
227 name = "upload" + System.currentTimeMillis() + "_";
228 fullpath = root + "/" + name;
229 f = new File(fullpath);
230 }
231 while(f.exists());
232
233 return name;
234 }
235
236 /***
237 * Cuts short name of a file from its fully qualified name. For
238 * example, "c:\a\b\info.txt" -> "info.txt".
239 *
240 * @param fullname Full name of a file.
241 * @return A String with the short name.
242 */
243 private String getShortName(String fullname)
244 {
245 int lastslash = fullname.lastIndexOf("/");
246 int lastbackslash = fullname.lastIndexOf("//");
247 int pos;
248
249 if (lastslash == lastbackslash)
250 {
251 pos = -1;
252 }
253 else if (lastslash > lastbackslash)
254 {
255 pos = lastslash + 1;
256 }
257 else
258 {
259 pos = lastbackslash + 1;
260 }
261
262 return fullname.substring(pos);
263 }
264
265 /***
266 * Finds the first position of B in StoreBuffer beginning with
267 * position number Pos, or -1 if not found.
268 *
269 * @param b Byte to find.
270 * @param pos Position to start from.
271 * @return The first occurence of B from Pos.
272 */
273 private int findByte(byte b, int pos)
274 {
275 if (pos < 0)
276 {
277 pos = 0;
278 }
279 else if (pos >= storebuffersize)
280 {
281 return -1;
282 }
283
284 for (int i = pos; i < storebuffersize ; i++)
285 {
286 if (storebuffer[i] == b)
287 {
288 return i;
289 }
290 }
291 return -1;
292 }
293
294 /***
295 * Finds the first position of SubArray in StoreBuffer beginning
296 * with position number Pos, or -1 if not found.
297 *
298 * @param subarray Subarray to find.
299 * @param pos Position to start from.
300 * @return The first occurence of Subarray from Pos.
301 */
302 private int findSubArray(byte[] subarray, int pos)
303 {
304 int sublen = subarray.length;
305 int maxpos, first, sp=0;
306
307 maxpos = storebuffersize - sublen;
308
309 for(first = pos ; (sp != sublen) && (first <= maxpos); first++)
310 {
311 first=findByte(subarray[0],first);
312 if ((first < 0) || (first > maxpos))
313 {
314 return - 1;
315 }
316
317 for (sp = 1 ; sp < sublen ; sp++)
318 {
319 if (storebuffer[first+sp] != subarray[sp])
320 {
321 sp = sublen;
322 }
323 }
324 }
325
326 if (sublen == 0)
327 {
328 return 0;
329 }
330 if (sp == sublen)
331 {
332 return (first - 1);
333 }
334 return -1;
335 }
336
337 /***
338 * Reads the data from the given inputstream to StoreBuffer.
339 *
340 * @param instream InputStream to use.
341 * @exception IOException.
342 */
343 private void readToStoreBuffer(InputStream instream)
344 throws IOException
345 {
346 int bufread;
347 int pos = 0;
348 BufferedInputStream bis =
349 new BufferedInputStream(instream, readbuffersize);
350
351 while ((bufread=bis.read(readbuffer)) != -1 &&
352 (maxdata >= pos || maxdata==0) )
353 {
354 System.arraycopy(readbuffer, 0, storebuffer, pos, bufread);
355 pos += bufread;
356 }
357 bis.close();
358 }
359
360 /***
361 * Finds values of Fieldname and Filename variables from the given
362 * chunk of StoreBuffer.
363 *
364 * @param start Starting position in StoreBuffer.
365 * @param end Ending position in StoreBuffer.
366 */
367 private void getHeaderInfo(int start, int end)
368 {
369 String temp = new String(storebuffer, start, end - start + 1);
370 int namestart, nameend;
371 int filenamestart, filenameend;
372 int conttypestart, conttypeend;
373
374 contenttype = null;
375 filename = null;
376
377 conttypestart = temp.indexOf("Content-Type: ");
378 if(conttypestart >= 0)
379 {
380 conttypestart += 14;
381 conttypeend = temp.length() - 1;
382 contenttype = temp.substring(conttypestart, conttypeend);
383 }
384
385 namestart = temp.indexOf("; name=\"") + 8;
386 nameend = temp.indexOf("\"", namestart);
387 fieldname = temp.substring(namestart, nameend);
388
389 filenamestart = temp.indexOf("; filename=\"", nameend + 1);
390 if (filenamestart >= 0)
391 {
392 filenamestart += 12;
393 filenameend = temp.indexOf("\"", filenamestart);
394 filename = temp.substring(filenamestart, filenameend);
395 }
396 }
397
398 /***
399 * Returns the given chunk of StoreBuffer as a String.
400 *
401 * @param start Starting position in StoreBuffer.
402 * @param end Ending position in StoreBuffer.
403 * @return Given chunk's representation as a String.
404 */
405 private String getChunkAsText(int start, int end)
406 {
407 String text = new String(storebuffer, start, end - start + 1);
408 return text;
409 }
410
411 /***
412 * Writes the given chunk of StoreBuffer to given OutputStream.
413 *
414 * @param start Starting position in StoreBuffer.
415 * @param end Ending position in StoreBuffer.
416 * @param outstream OutputStream to write to.
417 * @exception IOException.
418 */
419 private void storeChunk(int start,
420 int end,
421 OutputStream outstream)
422 throws IOException
423 {
424 BufferedOutputStream bos =
425 new BufferedOutputStream(outstream, readbuffersize);
426
427 bos.write(storebuffer, start, end - start + 1);
428 bos.flush();
429 bos.close();
430 }
431
432 /***
433 * Divides StoreBuffer into simple fields and binary fields
434 * (files) and writes them to files (simple fields - to a text
435 * file, files - to files with random names, providing name
436 * mappings in the file for simple fields).
437 *
438 * @exception IOException.
439 */
440 private void writeChunks()
441 throws IOException
442 {
443 int a;
444 int b;
445 int c = 0;
446 String savename = null;
447 String param = null;
448
449 b = findSubArray(boundary, 0);
450 do
451 {
452 if ((a = findSubArray(CRLF2, b + boundarysize)) >= 0)
453 {
454 if ((b = findSubArray(boundary, a + 4)) >= 0);
455 {
456 getHeaderInfo(c, a);
457 c = b;
458
459 if (filename == null || filename.length() == 0)
460 {
461 param = getChunkAsText(a + 4, b - 5);
462 org.apache.turbine.util.Log.info("FileUploader: received field: " + fieldname + "=" + param);
463 pp.add(fieldname, param);
464 }
465 else
466 {
467 // TODO: implement also retrieving enconding
468 // and other header info.
469
470 // TODO: strip the path information from the
471 // original filename.
472
473 String shortname = getShortName(filename);
474 savename = getRandomName() + shortname + ".dat";
475 String fullPath = root + "/" + savename;
476 org.apache.turbine.util.Log.info ("FileUploader: received file: field=" + fieldname + ", fullpath=" + filename + ", filename=" + shortname + ", saved to file: " + fullPath);
477 storeChunk(a + 4, b - 5,
478 new FileOutputStream(fullPath));
479 File f = new File(fullPath);
480 pp.add(this.PARAMETER_NAME_FILESIZE, f.length());
481 pp.add(this.PARAMETER_NAME_FILENAME, shortname);
482 pp.add(this.PARAMETER_NAME_FILENAME_SAVED, savename);
483 pp.add(this.PARAMETER_NAME_CONTENT_TYPE, contenttype);
484 }
485 }
486 }
487 }
488 while (a >= 0 && b >= 0);
489 }
490
491 /***
492 * Stores all data.
493 *
494 * @exception ServletException.
495 * @exception IOException.
496 * @deprecated Use TurbineUploadService counterpart FileItem.
497 */
498 public void saveStream()
499 throws ServletException,
500 IOException
501 {
502 readToStoreBuffer(req.getInputStream());
503 writeChunks();
504 }
505
506 /***
507 * Performs initialization.
508 *
509 * @param req An HttpServletRequest.
510 * @param res An HttpServletResponse.
511 * @param pp A ParameterParser.
512 * @deprecated Use TurbineUploadService counterpart FileItem.
513 */
514 public FileHandler(HttpServletRequest req,
515 HttpServletResponse res,
516 ParameterParser pp)
517 {
518 this.req = req;
519 this.res = res;
520 this.pp = pp;
521 this.root = "c:";
522
523 String conttype = req.getHeader("Content-Type");
524 if (conttype != null)
525 {
526 boundary = conttype.substring(conttype.indexOf("boundary") + 9).getBytes();
527 boundarysize = boundary.length;
528 storebuffersize = Integer.parseInt(req.getHeader("Content-Length"));
529 storebuffer = new byte[storebuffersize];
530 }
531 }
532
533 /***
534 * Performs initialization.
535 *
536 * @param req An HttpServletRequest.
537 * @param res An HttpServletResponse.
538 * @param pp A ParameterParser.
539 * @param root A String.
540 * @deprecated Use TurbineUploadService counterpart FileItem.
541 */
542 public FileHandler( HttpServletRequest req,
543 HttpServletResponse res,
544 ParameterParser pp,
545 String root )
546 {
547 this( req, res, pp );
548 this.setFileRepository(root);
549 }
550
551 /***
552 * Performs initialization.
553 *
554 * @param req An HttpServletRequest.
555 * @param res An HttpServletResponse.
556 * @param root A String.
557 * @deprecated Use TurbineUploadService counterpart FileItem.
558 */
559 public FileHandler( HttpServletRequest req,
560 ParameterParser pp,
561 String root )
562 {
563 this( req, null, pp );
564 this.setFileRepository(root);
565 }
566
567 /***
568 * Performs initialization.
569 *
570 * @param data A Turbine RunData object.
571 * @param root A String.
572 * @deprecated Use TurbineUploadService counterpart FileItem.
573 */
574 public FileHandler( RunData data,
575 String root )
576 {
577 this( data.getRequest(),
578 data.getResponse(),
579 data.getParameters(),
580 root );
581 }
582
583 /***
584 * Performs initialization.
585 *
586 * @param data A Turbine RunData object.
587 * @deprecated Use TurbineUploadService counterpart FileItem.
588 */
589 public FileHandler( RunData data )
590 {
591 this( data.getRequest(),
592 data.getResponse(),
593 data.getParameters() );
594 }
595
596 /***
597 * Sets the root file repository.
598 *
599 * @param root A String.
600 * @deprecated Use TurbineUploadService counterpart FileItem.
601 */
602 public void setFileRepository(String root)
603 {
604 this.root = root;
605 }
606
607 /***
608 * Gets the root file repository.
609 *
610 * @return A String.
611 * @deprecated Use TurbineUploadService counterpart FileItem.
612 */
613 public String getFileRepository()
614 {
615 return this.root;
616 }
617
618 /***
619 * Sets the maximum size.
620 *
621 * @param size A long.
622 * @deprecated Use TurbineUploadService counterpart FileItem.
623 */
624 public void setMaxSize(long size)
625 {
626 this.maxdata = size;
627 }
628
629 /***
630 * Deletes the file.
631 *
632 * @param filename A String.
633 * @return True if file was deleted.
634 * @deprecated Use TurbineUploadService counterpart FileItem.
635 */
636 public boolean deleteFile(String filename)
637 {
638 File f = new File(root + "/" + filename);
639 return f.delete();
640 }
641 }
This page was automatically generated by Maven